diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) Conrad Parker 2006
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+import Distribution.Simple
+main = defaultMain
diff --git a/cairo-appbase.cabal b/cairo-appbase.cabal
new file mode 100644
--- /dev/null
+++ b/cairo-appbase.cabal
@@ -0,0 +1,28 @@
+Cabal-Version:   >= 1.6
+Name:            cairo-appbase
+Version:         0.2
+Synopsis:        Template code for an app using GTK, Glade and Cairo graphics
+Description:     This is a template for building new GUI applications. The
+                 GTK widget layout is done via a Glade XML file which can be
+                 edited visually using glade.
+
+                 This template includes working callbacks to handle the File
+                 and Help menus and File Save/Open dialogs, with dummy
+                 handlers for selecting filenames and the Edit menu's
+                 cut/copy/paste.
+
+                 The main canvas for this application uses Cairo for
+                 graphics rendering, and includes example code from the
+                 cairo package.
+License:         BSD3
+License-file:    LICENSE
+Author:          Conrad Parker, Johan Bockgård
+Maintainer:      conrad@metadecks.org
+Category:        GUI
+Build-Depends:   base < 5, glib, gtk, glade, cairo
+Build-Type:      Simple
+Data-Files:      data/main.glade
+
+Executable:      cairo-appbase
+Main-Is:         cairo-appbase.hs
+Hs-Source-Dirs:  src
diff --git a/data/main.glade b/data/main.glade
new file mode 100644
--- /dev/null
+++ b/data/main.glade
@@ -0,0 +1,358 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">window1</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+
+  <child>
+    <widget class="GtkVBox" id="vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+	<widget class="GtkMenuBar" id="menubar1">
+	  <property name="visible">True</property>
+	  <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property>
+	  <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="menuitem1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_File</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="menu1">
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="new1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-new</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_new1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="open1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-open</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_open1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="save1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-save</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_save1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="save_as1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-save-as</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_save_as1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="quit1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-quit</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_quit1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="menuitem2">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_Edit</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="menu2">
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="cut1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-cut</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_cut1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="copy1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-copy</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_copy1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="paste1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-paste</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_paste1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkImageMenuItem" id="delete1">
+		      <property name="visible">True</property>
+		      <property name="label">gtk-delete</property>
+		      <property name="use_stock">True</property>
+		      <signal name="activate" handler="on_delete1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="menuitem3">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_View</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="menu3">
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkMenuItem" id="menuitem4">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_Help</property>
+	      <property name="use_underline">True</property>
+
+	      <child>
+		<widget class="GtkMenu" id="menu4">
+
+		  <child>
+		    <widget class="GtkMenuItem" id="about1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_About</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_about1_activate" last_modification_time="Sat, 05 Aug 2006 08:27:01 GMT"/>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkDrawingArea" id="drawingarea1">
+	  <property name="visible">True</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkStatusbar" id="statusbar1">
+	  <property name="visible">True</property>
+	  <property name="has_resize_grip">True</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkAboutDialog" id="aboutdialog1">
+  <property name="destroy_with_parent">False</property>
+  <property name="name" translatable="yes">Application Name</property>
+  <property name="wrap_license">False</property>
+  <property name="translator_credits" translatable="yes" comments="TRANSLATORS: Replace this string with your names, one name per line.">translator-credits</property>
+</widget>
+
+<widget class="GtkFileChooserDialog" id="opendialog">
+  <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+  <property name="local_only">True</property>
+  <property name="select_multiple">False</property>
+  <property name="show_hidden">False</property>
+  <property name="do_overwrite_confirmation">False</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">24</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="dialog-action_area1">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="button1">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="opendialog-Open-button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-open</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkFileChooserDialog" id="savedialog">
+  <property name="action">GTK_FILE_CHOOSER_ACTION_SAVE</property>
+  <property name="local_only">True</property>
+  <property name="select_multiple">False</property>
+  <property name="show_hidden">False</property>
+  <property name="do_overwrite_confirmation">False</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox2">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">24</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="dialog-action_area2">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="button2">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="button3">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-save</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/src/cairo-appbase.hs b/src/cairo-appbase.hs
new file mode 100644
--- /dev/null
+++ b/src/cairo-appbase.hs
@@ -0,0 +1,339 @@
+--
+-- Based on Gtk2Hs/demo/cairo/Drawing2.hs 
+-- Author: Johan Bockgård <bojohan@dd.chalmers.se>
+--
+-- This code is in the public domain.
+--
+
+import qualified System.Glib.Types as GTypes
+import qualified Graphics.UI.Gtk as G
+import qualified Graphics.UI.Gtk.Glade as Glade
+import qualified Graphics.Rendering.Cairo as C
+import qualified Graphics.Rendering.Cairo.Matrix as M
+
+import Paths_cairo_appbase as My
+
+windowWidth, windowHeight :: Int
+windowWidth   = 500
+windowHeight  = 500
+
+-- Write image to file
+writePng :: IO ()
+writePng =
+  C.withImageSurface C.FormatARGB32 width height $ \ result -> do
+      C.renderWith result $ example width height
+      C.surfaceWriteToPNG result "Draw.png"
+  where width  = windowWidth
+        height = windowHeight
+
+-- Display image in window
+main = do
+  G.initGUI
+
+  -- load up the glade file
+  filename <- My.getDataFileName "data/main.glade"
+  windowXmlM <- Glade.xmlNew filename
+  let windowXml = case windowXmlM of
+        (Just wX) -> wX
+        Nothing -> error ("can't find the glade file " ++ filename)
+      get :: (G.WidgetClass widget) => (GTypes.GObject -> widget) -> String -> IO widget
+      get = Glade.xmlGetWidget windowXml
+
+  -- get a handle on widgets from the glade file
+  window <- get G.castToWindow "window1"
+
+  -- set up File->New
+  new1 <- get G.castToMenuItem "new1"
+  G.onActivateLeaf new1 $ myNew
+
+  -- set up the File->Open dialog
+  open1 <- get G.castToMenuItem "open1"
+  openDialog <- get G.castToFileChooserDialog "opendialog"
+  G.onActivateLeaf open1 $ G.widgetShow openDialog
+  G.onResponse openDialog $ myFileOpen openDialog
+
+  -- set up the File->Save_As dialog
+  save1 <- get G.castToMenuItem "save1"
+  save_as1 <- get G.castToMenuItem "save_as1"
+  saveDialog <- get G.castToFileChooserDialog "savedialog"
+  G.onActivateLeaf save_as1 $ G.widgetShow saveDialog
+  G.onActivateLeaf save1 $ G.widgetShow saveDialog
+  G.onResponse saveDialog $ myFileSave saveDialog
+
+  -- set up Edit menu
+  cut1 <- get G.castToMenuItem "cut1"
+  G.onActivateLeaf cut1 $ myCut
+  copy1 <- get G.castToMenuItem "copy1"
+  G.onActivateLeaf copy1 $ myCopy
+  paste1 <- get G.castToMenuItem "paste1"
+  G.onActivateLeaf paste1 $ myPaste
+  delete1 <- get G.castToMenuItem "delete1"
+  G.onActivateLeaf delete1 $ myDelete
+
+  -- set up the Help->About dialog
+  about1 <- get G.castToMenuItem "about1"
+  aboutdialog1 <- get G.castToAboutDialog "aboutdialog1"
+  G.onActivateLeaf about1 $ G.widgetShow aboutdialog1
+  G.onResponse aboutdialog1 $ const $ G.widgetHide aboutdialog1
+
+  -- fix size
+  --   G.windowSetResizable window False
+  G.widgetSetSizeRequest window windowWidth windowHeight
+
+  -- quit on File->Quit menu selection
+  quit1 <- get G.castToMenuItem "quit1"
+  G.onActivateLeaf quit1 $ G.widgetDestroy window
+  G.onDestroy window G.mainQuit
+
+  -- set up the canvas
+  canvas <- get G.castToDrawingArea "drawingarea1"
+  G.onExpose canvas $ const (updateCanvas canvas)
+  G.widgetShowAll window
+  G.mainGUI
+
+myNew :: IO ()
+myNew = putStrLn "New"
+
+myFileOpen :: G.FileChooserDialog -> G.ResponseId -> IO ()
+myFileOpen fcdialog response = do
+  case response of
+    G.ResponseOk -> do Just filename <- G.fileChooserGetFilename fcdialog
+                       putStrLn filename
+    G.ResponseCancel -> putStrLn "Cancelled!"
+    G.ResponseDeleteEvent -> putStrLn "FileChooserDialog Deleted!"
+    G.ResponseClose -> putStrLn "Closed!"
+  G.widgetHide fcdialog
+
+myFileSave :: G.FileChooserDialog -> G.ResponseId -> IO ()
+myFileSave = myFileOpen
+
+myCut :: IO ()
+myCut = putStrLn "Cut"
+
+myCopy :: IO ()
+myCopy = putStrLn "Copy"
+
+myPaste :: IO ()
+myPaste = putStrLn "Paste"
+
+myDelete :: IO ()
+myDelete = putStrLn "Delete"
+
+updateCanvas :: G.DrawingArea -> IO Bool
+updateCanvas canvas = do
+  win <- G.drawingAreaGetDrawWindow canvas
+  (width, height) <- G.drawingAreaGetSize canvas
+  G.renderWithDrawable win $
+      example width height
+  return True
+
+----------------------------------------------------------------
+
+foreach :: (Monad m) => [a] -> (a -> m b) -> m [b]
+foreach = flip mapM
+
+keepState render = do
+  C.save
+  render
+  C.restore
+
+drawCircle x y r = do
+  C.arc x y r 0 (2 * pi)
+  fillStroke
+
+drawRectangle x y w h = do
+  C.rectangle x y w h
+  fillStroke
+
+stroke =
+  keepState $ do
+  C.setSourceRGBA 0 0 0 0.7
+  C.stroke
+
+fillStroke = do
+  C.fillPreserve
+  stroke
+
+----------------------------------------------------------------
+
+-- Example
+
+example width height = do
+  prologue width height
+  example1
+
+-- Set up stuff
+prologue wWidth wHeight = do
+  let width   = 10
+      height  = 10
+      xmax    = width / 2
+      xmin    = - xmax
+      ymax    = height / 2
+      ymin    = - ymax
+      scaleX  = realToFrac wWidth  / width
+      scaleY  = realToFrac wHeight / height
+
+  -- style and color
+  C.setLineCap C.LineCapRound
+  C.setLineJoin C.LineJoinRound
+  C.setLineWidth $ 1 / max scaleX scaleY
+  C.setSourceRGBA 0.5 0.7 0.5 0.5
+
+  -- Set up user coordinates
+  C.scale scaleX scaleY
+  -- center origin
+  C.translate (width / 2) (height / 2)
+  -- positive y-axis upwards
+  let flipY = M.Matrix 1 0 0 (-1) 0 0
+  C.transform flipY
+
+  grid xmin xmax ymin ymax
+
+
+-- Grid and axes
+grid xmin xmax ymin ymax =
+  keepState $ do
+  C.setSourceRGBA 0 0 0 0.7
+  -- axes
+  C.moveTo 0 ymin; C.lineTo 0 ymax; C.stroke
+  C.moveTo xmin 0; C.lineTo xmax 0; C.stroke
+  -- grid
+  C.setDash [0.01, 0.99] 0
+  foreach [xmin .. xmax] $ \ x ->
+      do C.moveTo x ymin
+         C.lineTo x ymax
+         C.stroke
+
+example1 = do
+  -- circles
+  drawCircle 0 0 1
+  drawCircle 2 2 3
+  -- a bunch of rectangles
+  keepState $
+    foreach [1 .. 5] $ \ _ ->
+        do drawRectangle 0 1 2 3
+           C.rotate (pi/8)
+  -- some cute stuff
+  thought
+  apple
+  snake
+
+thought =
+  keepState $ do
+  C.scale 0.04 0.04
+  C.translate (200) (380)
+  C.rotate pi
+  C.setSourceRGBA 0.5 0.5 1 0.7
+  C.setLineWidth 1
+  image
+  fillStroke
+  where
+    m = C.moveTo
+    c = C.curveTo
+    z = C.closePath
+    image = do
+        m 184 327
+        c 176 327 170 332 168 339
+        c 166 333 160 329 153 329
+        c 147 329 141 333 138 339
+        c 137 339 136 338 134 338
+        c 125 338 118 345 118 354
+        c 118 363 125 371 134 371
+        c 137 371 140 370 142 368
+        c 142 368 142 368 142 369
+        c 142 377 149 385 158 385
+        c 162 385 166 383 168 381
+        c 171 386 176 390 183 390
+        c 188 390 193 387 196 383
+        c 198 384 201 385 204 385
+        c 212 385 220 378 220 369
+        c 222 371 225 372 228 372
+        c 237 372 244 364 244 355
+        c 244 346 237 339 228 339
+        c 227 339 226 339 225 340
+        c 223 332 217 327 209 327
+        c 204 327 199 330 196 333
+        c 193 330 189 327 184 327
+        z
+        m 164 387
+        c 158 387 153 391 153 397
+        c 153 402 158 407 164 407
+        c 170 407 174 402 174 397
+        c 174 391 170 387 164 387
+        z
+        m 152 408
+        c 149 408 146 411 146 414
+        c 146 417 149 420 152 420
+        c 155 420 158 417 158 414
+        c 158 411 155 408 152 408
+        z
+        m 143 422
+        c 141 422 139 424 139 426
+        c 139 428 141 429 143 429
+        c 144 429 146 428 146 426
+        c 146 424 144 422 143 422
+        z
+
+apple =
+  keepState $ do
+  C.scale 0.05 0.05
+  C.translate (1110) (220)
+  C.rotate pi
+  C.setLineWidth 0.5
+  C.setSourceRGBA 0 0 0 0.7
+  image1
+  fillStroke
+  C.setSourceRGBA 1 0 0 0.7
+  image2
+  fillStroke
+  where
+    m = C.moveTo
+    c = C.curveTo
+    z = C.closePath
+    l = C.lineTo
+    image1 = do
+        m 1149 245
+        l 1156 244
+        l 1155 252
+        l 1149 245
+        z
+    image2 = do
+        m 1151 249
+        c 1145 249 1140 254 1140 261
+        c 1140 268 1145 273 1151 273
+        c 1152 273 1153 273 1154 272
+        c 1156 273 1157 273 1158 273
+        c 1164 273 1169 268 1169 261
+        c 1169 254 1164 249 1158 249
+        c 1157 249 1156 249 1154 250
+        c 1153 249 1152 249 1151 249
+        z
+
+snake =
+  keepState $ do
+  C.scale 0.04 0.04
+  C.translate (150) (220)
+  C.rotate pi
+  C.setLineWidth 0.5
+  C.setSourceRGBA 0.1 0.1 0 0.7
+  image
+  fillStroke
+  where
+    m = C.moveTo
+    c = C.curveTo
+    z = C.closePath
+    l = C.lineTo
+    image = do
+        m 146 320
+        c 143 308 130 314 123 319
+        c 115 324 108 311 100 314
+        c  93 317  92 319  81 318
+        c  76 318  60 309  60 320
+        c  60 328  73 321  82 323
+        c  94 326  98 317 106 320
+        c 113 323 120 330 128 323
+        c 133 318 142 312 146 320
+        l 146 320
+        z
+
+----------------------------------------------------------------
