diff --git a/hackInGhci.sh b/hackInGhci.sh
new file mode 100644
--- /dev/null
+++ b/hackInGhci.sh
@@ -0,0 +1,5 @@
+ghci -isrc src/Main.hs
+
+#ghci -isrc \
+#  -hide-package HAppS-Server-0.9.2.1 -i/home/thartman/haskellInstalls/smallInstalls/HAppS-Server-0.9.2.1/src \
+#  src/Main.hs
diff --git a/happs-tutorial.cabal b/happs-tutorial.cabal
--- a/happs-tutorial.cabal
+++ b/happs-tutorial.cabal
@@ -1,5 +1,5 @@
 Name:                happs-tutorial
-Version:             0.2
+Version:             0.3
 Synopsis:            A HAppS Tutorial that is is own demo
 Description:         A nice way to learn how to build web sites with HAppS
 
@@ -21,28 +21,43 @@
 Stability:           Experimental
 Category:            Web
 Build-type:          Simple
+
+-- when cabal install 1.6 comes out, hopefully can use * patterns for templates
+-- see http://hackage.haskell.org/trac/hackage/ticket/213
 Extra-Source-Files:
-    runServer.sh
-    templates/basic-url-handling.st templates/googleanalytics.st
-    templates/run-tutorial-locally.st
-    templates/home.st
-    templates/understanding-happs-types.st
-    templates/start-tutorial.st
+    runServerWithCompileNLink.sh
+    hackInGhci.sh
+    -- templates/*.st
+    static/tutorial.css
+    static/HAppSTutorialLogo.png
     templates/base.st
-    templates/login.st
-    templates/home_interpersonal.st
-    templates/myhomepage.st
-    templates/start-happs-on-boot.st
-    templates/moreFavoriteAnimals.st
+    templates/basic-url-handling.st
+    templates/errortemplate.st
     templates/footer.st
-    templates/main-function.st
+    templates/googleanalytics.st
+    templates/happs-slow-linking-bug.st
     templates/header.st
+    templates/home.st
+    templates/leastFavoriteAnimal.st
+    templates/login.st
+    templates/main-function.st
+    templates/menubar.st
+    templates/menuLoggedIn.st
+    templates/moreFavoriteAnimals.st
+    templates/my-favorite-animal.st
+    templates/newuser.st
     templates/prerequisites.st
-    templates/using-templates.st
-    templates/favoriteAnimal.st
-    static/tutorial.css
-    static/HAppSTutorialLogo.png
+    templates/register.st
+    templates/run-tutorial-locally.st
+    templates/start-happs-on-boot.st
+    templates/stringtemplate-basics.st
+    templates/tableofcontents.st
+    templates/templates-dont-repeat-yourself.st
+    templates/understanding-happs-types.st
+    templates/view-all-users.st
 
+
+
 Cabal-Version:       >= 1.2
 
 Executable happs-tutorial
@@ -51,16 +66,18 @@
         src
     Other-Modules:
         ControllerBasic
-        ControllerUsingTemplates  
         Misc   
         View
         Controller          
         Model  
         Session
-         
+        UserState         
+        SessionState
+        Session
     Build-Depends:   base >= 3, HStringTemplate, mtl, bytestring,
                      HAppS-Server, HAppS-Data, HAppS-State,
-                     containers
+                     containers, pretty
+
 
 
 
diff --git a/runServer.sh b/runServer.sh
deleted file mode 100644
--- a/runServer.sh
+++ /dev/null
@@ -1,1 +0,0 @@
-time ghc -isrc --make src/Main.hs; ./src/Main
diff --git a/runServerWithCompileNLink.sh b/runServerWithCompileNLink.sh
new file mode 100644
--- /dev/null
+++ b/runServerWithCompileNLink.sh
@@ -0,0 +1,14 @@
+
+# delete this later, this is only for diagnosing slow link times
+# at one point, we had almost 10 minute link times, and now it's down to 10 seconds
+# So we should do binary cuts on the repo and try to figure out exactly what changed and why
+# rm happs-tutorial src/*.hi  src/*.o 
+
+# time ghc -fwarn-missing-signatures -isrc --make src/Main.hs -o happs-tutorial
+time ghc -isrc --make src/Main.hs -o happs-tutorial
+
+beep -r 5
+
+./happs-tutorial 5001
+
+
diff --git a/src/Controller.hs b/src/Controller.hs
--- a/src/Controller.hs
+++ b/src/Controller.hs
@@ -1,53 +1,124 @@
+{-# OPTIONS_GHC -XPatternSignatures -fno-monomorphism-restriction #-}
 module Controller where
 
 import Control.Monad
 import Control.Monad.Trans
+import Data.List
 
 import HAppS.Server
-import Text.StringTemplate
 
-import Misc
+import Misc 
+
+-- state
+import HAppS.State
 import Session
+import SessionState
+import UserState
+
 import View
 
 import Model
+
 import ControllerBasic
-import ControllerUsingTemplates
 
------controller
--- Web server functions
+import Debug.Trace
+import Data.ByteString (unpack)
 -- SPs: ServerParts
+
+-- main controller
 controller :: [ServerPartT IO Response]
-controller = debugFilter $
-    tutorial ++ loginHandlers ++ simpleHandlers ++ usingTemplatesHandlers ++ staticfiles
+controller = {- debugFilter $ -} 
+    tutorial ++ simpleHandlers ++ [ myFavoriteAnimal ] ++ staticfiles 
+      ++ [ msgToSp "Quoth this server... 404." ]
 
 
-loginHandlers = [
-       dir "login" loginSPs
-       , dir "newuser" [methodSP POST $ withData newUserPage]
-       , dir "view" [withDataFn (liftM Just (readCookieValue "sid") `mplus` return Nothing) viewPage]
-       , dir "list" userListPage ]
-
-loginSPs = [methodSP GET $ ( ioMsgToSp . withBaseTemplateW [] ) "login" 
-            , methodSP POST $ withData loginPage ]
-
--- serve arbitrary io actions: read files, fetch from database 
-helloworldio = [ ioMsgToSp iovalue ] 
-  where iovalue :: IO HtmlString
-        iovalue = (return . HtmlString ) "hello<br>world"
-
 staticfiles = [ fileservedir "src" 
                 , fileservedir "static" ] 
 
 fileservedir d = dir d [ fileServe [] d ]
 
-templateservedir d  = dir d [ templateserve ]
-templateserve = ServerPartT $ \rq -> case rqPaths rq of
-                             [tmpl] -> ( ioMsgToWeb . withBaseTemplateW [] ) tmpl
-                             _ -> noHandle 
 
 tutorial = [
-         exactdir "/" [ ioMsgToSp $ withBaseTemplateW [] "home" ]
-         , dir "tutorial" [ templateserve ]
-       ] 
+    exactdir "/" [ tutlayoutSp1 [] "home" ]
+    , dir "tutorial" [
+        exactdir "/view-all-users" [ viewAllUsers ]
+        , lastPathPartSp (\rq tmpl -> ( tutlayoutReq rq []) tmpl ) -- tutlayoutSp [] 
+        , dir "actions" [
+            dir "login" [ methodSP POST $ withData loginPage  ]
+            , dir "newuser" [ methodSP POST $ do withData newUserPage ]
+            , dir "logout" [ logoutPage ] 
+        ]
+      ]
+    ]
+
+viewAllUsers = do
+  users <- anyRequest $  query ListUsers
+  tutlayoutSp1 [("userList", (paint users))] "view-all-users"
+  where paint xs = intercalate "<p>" xs
+
+-- A handler that renders a template with the template name specified in the argument
+tutlayoutSp1 attrs tmpl = withRequest $ \rq -> ( tutlayoutReq rq attrs ) tmpl 
+
+-- Render a template when the request has exactly one path segment left.
+-- The template that gets rendered is that path segment
+tutlayoutSp attrs = ServerPartT $ \rq -> 
+  case rqPaths rq of
+    [tmpl] -> ( tutlayoutReq rq attrs ) tmpl 
+    _ -> noHandle
+
+-- The final value is HtmlString so that the HAppS machinery does the right thing with toMessage.
+--   If the final value was left as a String, the page would display as text, not html.
+tutlayoutReq :: Request -> [([Char], String)] -> String -> WebT IO Response
+tutlayoutReq rq attrs tmpl = liftIO $ do
+  mbUser <- getmbLoggedInUser rq
+  attrs <- return $ maybe attrs (\user -> ("loggedInUser",user):attrs) mbUser
+  return . toResponse . HtmlString =<< tutlayout attrs tmpl 
+
+loginPage :: UserAuthInfo -> [ ServerPartT IO Response ] 
+loginPage (UserAuthInfo user pass) = [
+  ServerPartT $ \rq -> do
+    allowed <- query $ AuthUser user pass
+    if allowed 
+      then do startsess user ( {-traceWith dbg -} rq )
+      else ( tutlayoutReq rq [("errormsg","login error: invalid username or password")] ) "home"
+  ]
+  -- where dbg rq = "loginheaders: " ++ (show . {- rqHeaders -} getHeader "referer" $ rq) 
+
+
+
+startsess :: String -> Request -> WebT IO Response
+startsess user rq = do
+  key <- update $ NewSession (SessionData user)
+  addCookie (3600) (mkCookie "sid" (show key)) 
+  ( tutlayoutReq rq [("loggedInUser",user)] "home" )
+
+logoutPage :: ServerPartT IO Response
+logoutPage = 
+  withRequest $ \rq -> do
+    let mbSk = getMbSessKey rq
+    maybe 
+         ( return () )
+         ( update . DelSession )
+         mbSk
+    ( tutlayoutReq rq [] ) "home"   
+
+
+
+newUserPage :: NewUserInfo -> [ServerPartT IO Response]
+newUserPage (NewUserInfo user pass1 pass2) =
+  [ ServerPartT $ \rq -> 
+          if pass1 == pass2 
+             then do exists <- query $ IsUser user
+                     if exists
+                          then errW "User already exists" rq
+                          else do
+                            update $ ( AddUser user $ User user pass1 )
+                            startsess user rq
+             else errW "passwords did not match" rq
+  ]
+  where errW msg rq = ( tutlayoutReq rq [("errormsgRegister", msg)] ) "register" 
+
+
+
+
 
diff --git a/src/ControllerBasic.hs b/src/ControllerBasic.hs
--- a/src/ControllerBasic.hs
+++ b/src/ControllerBasic.hs
@@ -4,6 +4,8 @@
 import HAppS.Server
 import Misc
 import Data.Monoid
+import Control.Monad.Trans
+import Text.StringTemplate 
 
 {-
 ServerPartTs take a request to a response, approximately like so
@@ -33,7 +35,7 @@
 
 
 simpleHandlers :: [ServerPartT IO Response]
-simpleHandlers = debugFilter [
+simpleHandlers = [
 
   ServerPartT $ \rq -> do
     ru  <- (return . rqURL) rq
@@ -89,13 +91,13 @@
                   [ msgToSp "Another response generated using exactdir and msgToSp"] 
 
   , (exactdir "/ioaction"
-                  [ ioMsgToSp (return "This is an IO value.\
+                  [ ioMsgToSp (return $ HtmlString "This is an IO value.\
                                        \It could just as easily be the result of a file read operation,\
-                                       \or a database lookup." :: IO String) ] )
+                                       \or a database lookup." :: IO HtmlString) ] )
 
   , (exactdir "/ioaction2"
                   [ ioMsgToSp $ do slurp <- readFile "src/Main.hs"
-                                   return $  "Let's try reading the Main.hs file: .....\n" ++ slurp ])
+                                   return $ HtmlString $ "Let's try reading the Main.hs file: .....\n" ++ slurp ])
 
   , (exactdir "/htmlAttemptWrong"
                   [msgToSp "first try at displaying <font color=\"red\">red formatted</font> html (wrong)"])
@@ -111,8 +113,28 @@
 -- pretty much useless little server part constructor, for demo purposes
 simplematch :: String -> TutHandler
 simplematch u = ServerPartT $ \rq -> do
-    ru <- (return . rqURL) rq
+    let ru = rqURL rq
     if ru == ("/simplematch" ++ u)
        then ( return . toResponse ) ( "matched " ++ u) 
        else noHandle :: TutWebT 
 
+-- don't like these functions, feel they obfuscate. 
+-- I wrote them when I had a less good understanding 
+-- oh well, at least I don't use them in "real" code. (eg, took this out of misc.)
+msgToSp :: (Monad m, ToMessage a) => a -> ServerPartT m Response
+msgToSp = anyRequest . msgToWeb
+msgToWeb :: (Monad m, ToMessage a) => a -> WebT m Response
+msgToWeb = return . toResponse
+ioMsgToSp = anyRequest .  liftIO . ( return . toResponse =<< ) 
+
+myFavoriteAnimal :: ServerPartT IO Response
+myFavoriteAnimal = 
+  exactdir "/usingtemplates/my-favorite-animal"    
+        [ ServerPartT $ \rq ->
+            liftIO $ do templates <- directoryGroup "templates"
+                        return . toResponse . HtmlString . 
+                            renderTemplateGroup templates [("favoriteAnimal", "Tyrannasaurus Rex")
+                                                           , ("leastFavoriteAnimal","Bambi")]
+                                                    $ "my-favorite-animal" 
+        ]
+  
diff --git a/src/ControllerUsingTemplates.hs b/src/ControllerUsingTemplates.hs
deleted file mode 100644
--- a/src/ControllerUsingTemplates.hs
+++ /dev/null
@@ -1,42 +0,0 @@
-{-# OPTIONS -XPatternSignatures #-}
-module ControllerUsingTemplates where 
-
-import HAppS.Server
-import Misc
-import Data.Monoid
-
-import View
-import Text.StringTemplate
-
-
-usingTemplatesHandlers :: [ServerPartT IO Response]
-usingTemplatesHandlers = debugFilter [
-  dir "usingtemplates"
-    [ exactdir "/testtgio"
-        [ ioMsgToSp ( withTutTemplate $ renderDef [("favoriteAnimal", "giraffe")] "myhomepage" ) ]
-    ]
-  ]
-
-
-
-
-
--- generate some html, from templates in templates directory
-{-
-generatePages = do
-
-
-  -- should probably change this to directoryGroup or directoryGroupLazy in production code
-  -- but not sure which one is better... figure it out later.
-  (tg :: STGroup String) <- unsafeVolatileDirectoryGroup "templates" 1 -- 1 second reload time
-
-  (writeFile "myHomepage.html" . genMyHomepage) tg
-  (writeFile "moreFavoriteAnimals.html" . genMoreFavoriteAnimals) tg
-  where 
-    genMyHomepage  = toString . setAttribute "favoriteAnimal" "giraffe" . (getStringTemplateDef "myhomepage")
-    genMoreFavoriteAnimals = toString 
-                               . optInsertTmpl [("separator","<p>\n")]
-                               . setAttribute "favoriteAnimals" favoriteAnimals 
-                               . getStringTemplateDef "moreFavoriteAnimals"
-    favoriteAnimals = ["guppies","mayflies","dinosaurs"]
--}
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -6,10 +6,31 @@
 import Model
 import Controller
 import Misc
+import System.Environment
+import HAppS.State
+import Session
 
 main = do
-  let p = 5001 
+  -- let p = 5001 
+  let usageMessage = "usage example: happs-tutorial 5001 (starts the app on port 5001)"
+  args <- getArgs
+  case args of
+    [port] -> runserver (read port)
+    otherwise -> do
+              putStrLn usageMessage
+              
+
+-- run the happs server on some port
+runserver p = do
   startSystemState entryPoint -- start the HAppS state system
-  putStrLn $ "starting on port " ++ (show p)
+  putStrLn $ "happs tutorial starting on port " ++ (show p) ++ "\n" ++
+             "shut down with ctrl-c"
+             
   simpleHTTP (Conf {port=p}) controller -- start serving web pages
+  where entryPoint :: Proxy TutorialState
+        entryPoint = Proxy
+runInGhci = do
+    putStrLn $ "happs tutorial running ins ghci. \n" ++
+             "exit :q ghci completely and reenter ghci, before restarting."
+    runserver 5001
 
diff --git a/src/Misc.hs b/src/Misc.hs
--- a/src/Misc.hs
+++ b/src/Misc.hs
@@ -6,57 +6,39 @@
 import qualified Data.ByteString.Lazy.Char8 as L
 import Control.Monad.Trans
 import Data.List
+
 import Debug.Trace
+import Text.PrettyPrint as PP
+
 import Text.StringTemplate
 import Data.Monoid
+import Control.Monad.Reader
 
 newtype HtmlString = HtmlString String
 instance ToMessage HtmlString where
   toContentType _ = B.pack "text/html"
   toMessage (HtmlString s) = L.pack s 
 
-instance ToMessage (StringTemplate String) where
-  toContentType _ = B.pack "text/html"
-  toMessage = L.pack . toString  
-
-{-  
-exactdir :: Monad m => String -> [ServerPartT m a] -> ServerPartT m a
-exactdir staticPath handlers
-    = ServerPartT $ \rq -> if ( \rq' -> ( rqURL rq' == staticPath ) ) rq
-                             then (\rq' -> unServerPartT (mconcat handlers) rq') rq
-                             else mempty
--}
-exactdir staticPath = spCatIf rqmatch
-  where rqmatch rq = rqURL rq == staticPath
-
--- concat handlers if...
-spCatIf rqmatch handlers = ServerPartT h
-  where h rq = if rqmatch rq then unServerPartT (mconcat handlers) rq else mempty
-
-traceTrue x = trace (show x) True
-
-
-msgToWeb :: (Monad m, ToMessage a) => a -> WebT m Response
-msgToWeb = return . toResponse
+exactdir staticPath = spsIf (\rq -> rqURL rq == staticPath) 
 
-ioMsgToWeb :: (ToMessage a) => IO a -> WebT IO Response
-ioMsgToWeb ios = liftIO $ do s <- ios
-                             ( return . toResponse ) s
+spsIf :: (Monad m) => (Request -> Bool) -> [ServerPartT m a] -> ServerPartT m a
+spsIf p sps = withRequest $ \rq ->
+  if p rq
+    then unServerPartT (mconcat sps) rq
+    else mempty
 
-msgToSp :: (Monad m, ToMessage a) => a -> ServerPartT m Response
-msgToSp = anyRequest . msgToWeb
+traceTrue x = trace (show x ++ "\n\n") True
+traceIt x = trace (show x ++ "\n\n") x
+traceMsg msg x = trace ( "\n\n" ++ msg ++ (show x) ++ "\n\n") x
+traceReadableMsg msg x = trace ( "\n\n" ++ msg ++ (show . show $ x) ++ "\n\n") x
 
-ioMsgToSp :: (ToMessage a) => (IO a) -> ServerPartT IO Response
-ioMsgToSp = anyRequest . ioMsgToWeb
-traceIt x = trace (show x) x
-traceMsg msg x = trace ( msg ++ (show x) ) x
+pp[] = ( PP.render . vcat . map text . map show )
+traceWith f v = trace (f v) v
 
 
 instance (Monad m) => Monoid (ServerPartT m a)
   where mempty = ServerPartT $ \rq -> noHandle
         mappend a b = ServerPartT $ \rq -> (unServerPartT a rq) `mappend` (unServerPartT b rq) 
-
-
 instance (Monad m) => Monoid (WebT m a) where
   mempty = noHandle
   mappend a b = WebT $ do a' <- unWebT a
@@ -64,12 +46,44 @@
                               NoHandle -> unWebT b
                               _        -> return a'
 
-renderDef :: [(String,String)] -> String -> STGroup String -> StringTemplate String
-renderDef attrs tmplname grp =
-    maybe ( error $ "template not found: " ++ tmplname )
-          ( setManyAttrib attrs )
-          ( getStringTemplate tmplname grp )
+renderTemplateGroup :: (STGroup String) -> [(String, String)] -> String -> String
+renderTemplateGroup gr attrs tmpl = 
+   toString $
+       maybe ( error $ "template not found: " ++ tmpl )
+             ( setManyAttrib attrs )
+             ( getStringTemplate tmpl gr )
 
--- withTemplateDir :: String -> (STGroup String -> String) -> IO String
-withTemplateDir tdir f = return . f =<< unsafeVolatileDirectoryGroup tdir 1
+
+----------------- reading data ----------------
+readData :: RqData a -> Request -> Maybe a
+readData rqDataReader rq = runReaderT rqDataReader $ (rqInputs rq,rqCookies rq)  
+readDataDef :: b -> (a -> b) -> RqData a -> Request -> b
+readDataDef def f rqDataReader rq = maybe def f . readData rqDataReader $ rq
+
+dataReaderToWeb :: RqData a -> Request -> WebT IO (Maybe a)
+dataReaderToWeb rqDataReader rq = return . readData rqDataReader $ rq
+dataReaderToWebDef :: b -> (a -> b) -> RqData a -> Request -> WebT IO b
+dataReaderToWebDef def f rqDataReader rq = return . readDataDef def f rqDataReader $ rq
+
+dataReaderToSp :: RqData a -> ServerPartT IO (Maybe a)
+dataReaderToSp rqDataReader = withRequest $ \rq -> dataReaderToWeb rqDataReader rq
+dataReaderToSpDef :: b -> (a->b) -> RqData a -> ServerPartT IO b
+dataReaderToSpDef def f rqDataReader = withRequest $ \rq -> dataReaderToWebDef def f rqDataReader rq
+
+alltrue ps x = foldr g True ps
+  where g p b = b && p x
+nonetrue ps x = alltrue (map ( not . ) ps) x
+  
+
+-- Do something when the request has exactly one path segment left.
+-- lastPathPartSp :: (Request -> String -> WebT IO Response) -> ServerPartT IO Response
+lastPathPartSp f = ServerPartT $ \rq ->
+  case rqPaths rq of
+            [lastpart] -> f rq lastpart
+            _ -> noHandle
+
+ifFirstPathPartSp pathpart f = ServerPartT $ \rq ->
+  case rqPaths rq of
+            (x:xs) -> f rq pathpart
+            _ -> noHandle
 
diff --git a/src/Model.hs b/src/Model.hs
--- a/src/Model.hs
+++ b/src/Model.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS -XPatternSignatures -fno-monomorphism-restriction #-}
 module Model where
 
 import Control.Monad
@@ -5,53 +6,39 @@
 import HAppS.Server
 import Session
 import Misc
-import View
+import SessionState
+-- import UserState
+import Control.Monad.Trans
 
 -------state
 data UserAuthInfo = UserAuthInfo String String
 data NewUserInfo = NewUserInfo String String String
 
 instance FromData UserAuthInfo where
-    fromData = liftM2 UserAuthInfo (look "username") (look "password" `mplus` return "nopassword")
+    fromData = liftM2 UserAuthInfo (look "username")
+                                   (look "password" `mplus` return "nopassword")
 
 instance FromData NewUserInfo where
-    fromData = liftM3 NewUserInfo (look "username") (look "password" `mplus` return "nopassword") (look "password2" `mplus` return "nopassword2")
-
-entryPoint :: Proxy State
-entryPoint = Proxy
-
--- handlers that affect state
-loginPage (UserAuthInfo user pass) = [anyRequest $ do
-  allowed <- query $ AuthUser user pass
-  if allowed
-    then performLogin user
-    else msgToWeb "Incorrect password"
-  ]
-
-performLogin user = do
-  key <- update $ NewSession (SessionData user)
-  addCookie (-1) (mkCookie "sid" (show key))
-  msgToWeb $ "UserAuthInfo: " ++ show (user)
+    fromData = liftM3 NewUserInfo (look "username")
+                                  (look "password" `mplus` return "nopassword")
+                                  (look "password2" `mplus` return "nopassword2")
 
-checkAndAdd user pass = do
-  exists <- query $ IsUser user
-  if exists
-    then msgToWeb $ "User already exists"
-    else do
-      update $ ( AddUser user $ User user pass )
-      msgToWeb $ "User created."
+-- getMbSessKey rq = readData (readCookieValue "sid") rq
+getMbSessKey :: Request -> Maybe SessionKey
+getMbSessKey rq | traceTrue "getMbSessKey, rq" = traceWith ( ("sidCookie: " ++) . show ) $ readData (readCookieValue "sid") (traceReadableMsg "rq: " rq)
 
-viewPage (Just sid) = [anyRequest $ do
-  ses <- query $ (GetSession $ sid)
-  ( ( ioMsgToWeb . withBaseContentW ) $ "Cookie value: " ++ (maybe "not logged in" show (ses :: Maybe SessionData)) :: WebT IO Response)]
-viewPage Nothing =
-  [ msgToSp "Not logged in"]
+getmbLoggedInUser :: Request -> IO (Maybe String)
+getmbLoggedInUser rq = do
+  mbSd <- getMbSessData rq
+  return $ do
+    sd <- mbSd
+    Just . sesUser $ sd
 
-newUserPage (NewUserInfo user pass1 pass2)
-  | pass1 == pass2 = [anyRequest $ do (checkAndAdd user pass1)]
-  | otherwise = [ msgToSp "Passwords did not match"]
+getMbSessData :: Request -> IO (Maybe SessionData)                          
+getMbSessData rq = do
+  let mbSk = getMbSessKey rq
+  maybe ( return Nothing )
+        ( query . GetSession )
+        mbSk
 
-userListPage :: [ServerPartT IO Response]
-userListPage = [anyRequest $ do u <- query ListUsers
-                                ( ioMsgToWeb . withBaseContentW ) $ "Users: " ++ (show u)]
 
diff --git a/src/Session.hs b/src/Session.hs
--- a/src/Session.hs
+++ b/src/Session.hs
@@ -1,87 +1,90 @@
-{-# OPTIONS -fglasgow-exts #-}
-{-# LANGUAGE TemplateHaskell , FlexibleInstances, UndecidableInstances, OverlappingInstances,
-             MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE TemplateHaskell, FlexibleInstances, FlexibleContexts, 
+             MultiParamTypeClasses, DeriveDataTypeable, TypeFamilies,
+             TypeSynonymInstances #-}
 
 module Session where  
 
 import qualified Data.Map as M
-import Control.Monad
 import Control.Monad.Reader
 import Control.Monad.State (modify,put,get,gets)
-import Data.Generics hiding ((:+:))
-import HAppS.Server
+import Data.Generics
 import HAppS.State
-import HAppS.Data
-
-type SessionKey = Integer                                                                   
-
-data SessionData = SessionData {                                                            
-  sesUser :: String
-} deriving (Read,Show,Eq,Typeable,Data)                                                     
+import SessionState
+import UserState
 
-data Sessions a = Sessions {unsession::M.Map SessionKey a}                                  
-  deriving (Read,Show,Eq,Typeable,Data)
   
-data State = State {                                                                        
+data TutorialState = TutorialState {                                                                        
   sessions :: Sessions SessionData,                                                         
   users :: M.Map String User
 } deriving (Show,Read,Typeable,Data)                                                        
 
-data User = User {                                                                          
-  username :: String,                                                                       
-  password :: String
-} deriving (Show,Read,Typeable,Data)                                                        
+instance Version TutorialState                                                                      
 
-instance Version SessionData                                                                
-instance Version (Sessions a)                                                               
+$(deriveSerialize ''TutorialState)                                                                  
 
-$(deriveSerialize ''SessionData)                                                            
-$(deriveSerialize ''Sessions)
+instance Component TutorialState where                                                              
+  type Dependencies TutorialState = End                                                             
+  initialValue = TutorialState { sessions = (Sessions M.empty),
+                         users = M.empty }                                           
 
-instance Version State                                                                      
-instance Version User
+authUser :: String -> String -> Query TutorialState Bool  
+authUser name pass = do
+  users <- askUsers
+  return $ (Just pass) == liftM password (M.lookup name users)
 
-$(deriveSerialize ''User)                                                                   
-$(deriveSerialize ''State)                                                                  
 
-instance Component State where                                                              
-  type Dependencies State = End                                                             
-  initialValue = State (Sessions M.empty) M.empty                                           
-  
-askUsers :: MonadReader State m => m (M.Map String User)                                    
+askUsers :: Query TutorialState (M.Map String User)                                    
 askUsers = return . users =<< ask
 
-askSessions::MonadReader State m => m (Sessions SessionData)                                
+askSessions :: Query TutorialState (Sessions SessionData)
 askSessions = return . sessions =<< ask
 
-modUsers f = modify (\s -> (State (sessions s) (f $ users s)))                              
-modSessions f = modify (\s -> (State (f $ sessions s) (users s)))                           
+modUsers :: ( M.Map String User -> M.Map String User ) -> Update TutorialState ()
+modUsers f = modify (\s -> (TutorialState (sessions s) (f $ users s)))                              
 
+
+
+modSessions :: (Sessions SessionData -> Sessions SessionData) -> Update TutorialState ()
+modSessions f = modify (\s -> (TutorialState (f $ sessions s) (users s)))                           
+
+isUser :: String -> Query TutorialState Bool
 isUser name = liftM (M.member name) askUsers                                                
 
+
+addUser :: String -> User -> Update TutorialState ()
 addUser name u = modUsers $ M.insert name u                                                 
 
-authUser name pass = do
-  users <- askUsers
-  return $ (Just pass) == liftM password (M.lookup name users)
 
-listUsers :: MonadReader State m => m [String]
-listUsers = liftM M.keys askUsers
 
-setSession key u = do
-  modSessions $ Sessions . (M.insert key u) . unsession
-  return ()
+listUsers :: Query TutorialState [String]
+listUsers = liftM M.keys askUsers
 
+newSession :: SessionData -> Update TutorialState SessionKey
 newSession u = do
   key <- getRandom
-  setSession key u
+  modSessions $ Sessions . (M.insert key u) . unsession
   return key
 
-getSession::SessionKey -> Query State (Maybe SessionData)
-getSession key = liftM ((M.lookup key) . unsession) askSessions
+delSession :: SessionKey -> Update TutorialState ()
+delSession sk = modSessions $ Sessions . (M.delete sk) . unsession
 
-numSessions:: Proxy State -> Query State Int
-numSessions = proxyQuery $ liftM (M.size . unsession) askSessions
 
-$(mkMethods ''State ['addUser, 'authUser, 'isUser, 'listUsers, 'setSession, 'getSession, 'newSession, 'numSessions])
+getSession::SessionKey -> Query TutorialState (Maybe SessionData)
+getSession key = liftM (M.lookup key . unsession) askSessions
 
+numSessions :: Query TutorialState Int
+numSessions  =  liftM (M.size . unsession) askSessions
+
+-- define types which are upper case of methods below, eg AddUser, AuthUser...
+-- these types work with HApppS query/update machinery
+-- in ghci, try :i AddUser
+$(mkMethods ''TutorialState
+    ['addUser
+     ,'authUser
+     ,'isUser
+     , 'listUsers
+     , 'getSession
+     , 'newSession
+     , 'delSession
+     , 'numSessions]
+ )
diff --git a/src/SessionState.hs b/src/SessionState.hs
new file mode 100644
--- /dev/null
+++ b/src/SessionState.hs
@@ -0,0 +1,27 @@
+{-# OPTIONS_GHC -XDeriveDataTypeable #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module SessionState where
+
+import HAppS.State
+import Data.Generics
+import qualified Data.Map as M
+
+
+type SessionKey = Integer                                                                   
+
+data SessionData = SessionData {                                                            
+  sesUser :: String
+} deriving (Read,Show,Eq,Typeable,Data)                                                     
+
+
+data Sessions a = Sessions {unsession::M.Map SessionKey a}                                  
+  deriving (Read,Show,Eq,Typeable,Data)
+
+
+instance Version SessionData                                                                
+instance Version (Sessions a)
+
+$(deriveSerialize ''SessionData)                                                            
+$(deriveSerialize ''Sessions)
+
diff --git a/src/UserState.hs b/src/UserState.hs
new file mode 100644
--- /dev/null
+++ b/src/UserState.hs
@@ -0,0 +1,17 @@
+{-# OPTIONS_GHC -XDeriveDataTypeable #-}
+{-# LANGUAGE TemplateHaskell #-}
+module UserState where
+import HAppS.State
+import Data.Generics
+-- import Data.Typeable
+--import Control.Monad.Reader
+--import Control.Monad.State
+
+data User = User {                                                                          
+  username :: String,                                                                       
+  password :: String
+} deriving (Show,Read,Typeable,Data)
+
+instance Version User
+
+$(deriveSerialize ''User) 
diff --git a/src/View.hs b/src/View.hs
--- a/src/View.hs
+++ b/src/View.hs
@@ -1,23 +1,98 @@
-{-# OPTIONS -fglasgow-exts -fno-monomorphism-restriction #-}
 module View where
 
 import Text.StringTemplate
 import Misc
+import Text.StringTemplate
+import qualified Data.Map as M
+import Data.Char
 
-getTutTemplates = unsafeVolatileDirectoryGroup "templates" 1 -- 1 second reload time
+-- Notice, there are no HApps.* imports 
+-- Idea is, view is meant to be used from controller.
+-- Try to keep functions as type
+--   Pure -> .. -> Pure -> IO String
+--   or Pure -> Pure -> String
 
--- plug a base templatate with a string which is based on a template file
-withBaseTemplateW :: [(String,String)] -> String -> IO (StringTemplate String)
-withBaseTemplateW attrs contentTmpl = do
-  content <- return . toString =<< renderTut attrs contentTmpl
-  withBaseContentW content
+-- 1 second reload time/IO for templates.
+-- tmplkvs: key/value pairs used for filling in a template
+tutlayout, tutlayoutSafe :: [(String, String)] -> String -> IO String
+tutlayout tmplkvs tmpl = tutlayout' (unsafeVolatileDirectoryGroup "templates" 1) tmplkvs tmpl
+-- how much stress does this put on the server?
+-- how could I even find this out?
+-- I could try setting a higher reload time, run top, and see if the happs process uses less memory
+-- withTemplateDir :: String -> (STGroup String -> String) -> IO String
+-- Could also see if it's practical to try working with the safe version
+-- Probably it's fine for "production", where not making template changes all the time
+-- and it's fine to stop/restart server when I do.
+tutlayoutSafe tmplkvs tmpl = tutlayout' (directoryGroup "templates")  tmplkvs tmpl 
 
--- plug a base template with a string
-withBaseContentW :: String -> IO (StringTemplate String)
-withBaseContentW content = renderTut [("contentarea",content)] "base"
-  
-renderTut :: [(String,String)] -> String -> IO ( StringTemplate String )
-renderTut attrs tmpl = withTutTemplate ( renderDef attrs tmpl )
+tutlayout' :: IO (STGroup String) -> [(String, String)] -> String -> IO String
+tutlayout' f tmplkvs tmpl = do
+  templates <- f 
 
-withTutTemplate :: (STGroup String -> a) -> IO a
-withTutTemplate = withTemplateDir "templates" 
+  let rendertut kvs tmpl = ( renderTemplateGroup templates ) kvs tmpl
+
+      content = rendertut tmplkvs  tmpl
+      kvMenustyleActivelink = getMenuCssStyles tmpl      
+      userMenu = maybe 
+        ( rendertut (tmplkvs ++ kvMenustyleActivelink) "login" )
+        ( \user -> rendertut [("user",user)] "menuLoggedIn" )
+        ( lookup "loggedInUser" tmplkvs )
+      header =  rendertut (kvMenustyleActivelink ++ [("userMenu",userMenu)] ) "header"
+      toc = rendertut kvMenustyleActivelink "tableofcontents" 
+
+  return $ rendertut ( [("tocarea",toc)
+                     , ("contentarea",content)
+                     , ("headerarea",header)] ) "base"
+
+getMenuCssStyles :: String -> [(String,String)]
+getMenuCssStyles tmpl = 
+  maybe
+    defaultMenuActivelinks
+    tweakCssStyles
+    mbActiveLink
+  where defaultMenuActivelinks = zip ( map snd kvTmplMenucontrol ) ( repeat "menuitem" )
+        mbActiveLink = lookup tmpl kvTmplMenucontrol
+        tweakCssStyles menuControlVar = map highlightselected defaultMenuActivelinks
+          where highlightselected (mv,style) | mv == menuControlVar = (mv,"menuItemSelected")
+                highlightselected a | otherwise = a
+        
+
+-- In header and table of contents menus: 
+-- style "menuItemSelected" makes a colored link
+-- style "menuItem" is default
+-- default for menu control is no menu item is highlighted
+-- Some templates trigger a menu link color change
+-- Some templates have no effect
+-- This is controlled at the template level by using "menustyle_somepage" type vars 
+-- to control css, and in the following list, which controls which templates that style
+-- will have an effect in
+-- In all cases, the template named "sometmpl" will have an active menu item which is controlled by the template variable
+-- "menustyleSometmpl"
+-- url-with_dashes would be controlled with var menustyleUrlwithdashes
+-- (Template system doens't like punctuation in template vars)
+kvTmplMenucontrol :: [(String,String)]
+kvTmplMenucontrol = map stylify
+                      [ "home"
+                        , "view-all-users"
+                        , "login"
+                        , "register"
+
+                        , "prerequisites"
+                        , "overview"
+                        , "run-tutorial-locally"
+                        , "main-function"
+                        , "basic-url-handling"
+                        , "templates-dont-repeat-yourself"
+                        , "stringtemplate-basics"
+                        , "start-happs-on-boot"
+                        
+                      ]
+  where -- how to do this with Control.Arrow?
+        stylify tmpl = (tmpl, ( ("menustyle" ++ ) . capitalize . stripPunctuation . (map toLower) ) tmpl)
+        capitalize [] = []
+        capitalize (x:xs) = toUpper x : xs
+        stripPunctuation = filter $ alltrue $ map (/=) [ '-', '_' ] 
+
+
+
+
diff --git a/static/tutorial.css b/static/tutorial.css
--- a/static/tutorial.css
+++ b/static/tutorial.css
@@ -4,17 +4,53 @@
 
 /* p{margin:0 10px 10px} */
 
-a{color: #006}
+/* a{color: green} */ /* 006 */ 
 
 div#header{position:relative}
+
+/*
 div#header h1{
-  height:70px;line-height:70px;margin:0;
-  padding-left:10px;background: #EEE;color: #79B30B}
+  height:70px;
+  line-height:70px;
+  margin:0;
+  padding-left:10px;
+  background: #EEE;
+  color: #79B30B}
+*/
+
+
 div#header h4{  
   margin:0;
-  padding-left:120px;background: #EEE;}
-div#header a{background: #EEE;height:80px} 
+  padding-left:10px;
+  background: #EEE;
+  a{color: green}
+}
 
+
+div#header a {
+  /* color: green; */
+
+
+}
+
+/* menu colors */
+a.menuitem:link {color: blue}
+a.menuitem:active {color: blue}
+a.menuitem:visited {color: blue}
+a.menuitem:hover {color: blue}
+a.menuitemselected:link {color: red}
+a.menuitemselected:active {color: red}
+a.menuitemselected:visited {color: red}
+a.menuitemselected:hover {color: red}
+
+
+
+
+
+/* div#header a{background: #EEE;height:80px}  */
+
+
+
 /* div#content p{line-height:1.4} */
 
 div#content
@@ -78,3 +114,4 @@
 .btn { background-color:#e9e9e9;
        border: 1px solid #336699; 
        margin: 0 5px 0 5px; vertical-align: bottom }
+
diff --git a/templates/base.st b/templates/base.st
--- a/templates/base.st
+++ b/templates/base.st
@@ -1,9 +1,26 @@
-$ header() $
-    <div id="content"> 
-      $ contentarea $      
-    </div> 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+      <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+      <title> HAppS Tutorial </title>
+      <link rel="stylesheet" href="/static/tutorial.css" type="text/css" />
+    </head>
 
-$ googleanalytics() $ 
+    <body>
 
-$ footer() $
+        
+	$ headerarea $
+	    <div id="content"> 
+	      <table> <tr> <td valign=top width = 200> $ tocarea $ </td> 
+		      <td> $ contentarea $ </td>
+                      <td width=100></td>
+	      </tr> </table>
+	    </div> 
 
+	$! googleanalytics() !$ 
+
+	$ footer() $
+
+    </body>
+</html>
diff --git a/templates/basic-url-handling.st b/templates/basic-url-handling.st
--- a/templates/basic-url-handling.st
+++ b/templates/basic-url-handling.st
@@ -51,4 +51,4 @@
 
 <p>The static file serving example above hints at the templating system used by this tutorial to put together web pages behind the scenes.</p>
 
-<p>We learn about <a href="/tutorial/using-templates">using-templates</a> next.</p>
+<p>We learn about <a href="/tutorial/templates-dont-repeat-yourself">using templates with HAppS</a> next.</p>
diff --git a/templates/errortemplate.st b/templates/errortemplate.st
new file mode 100644
--- /dev/null
+++ b/templates/errortemplate.st
@@ -0,0 +1,3 @@
+<font color=red>
+  $ errormsg $
+</font>
diff --git a/templates/favoriteAnimal.st b/templates/favoriteAnimal.st
deleted file mode 100644
--- a/templates/favoriteAnimal.st
+++ /dev/null
@@ -1,3 +0,0 @@
-Again, my favorite animal is a $ favoriteAnimal $. (set in another template)
-<p>
-If I forget to set an attribute (favoriteMammal), it just doesn't display: $ favoriteMammal $
diff --git a/templates/footer.st b/templates/footer.st
--- a/templates/footer.st
+++ b/templates/footer.st
@@ -1,6 +1,5 @@
     <div id="footer">
-    <!-- {% block footer %}
-    {% endblock %} -->
+    copyright thomashartman1 at gmail 
+    <br><a href="http://code.haskell.org/happs-tutorial">use the source</a>
     </div>
-</body>
-</html>
+    
diff --git a/templates/happs-slow-linking-bug.st b/templates/happs-slow-linking-bug.st
new file mode 100644
--- /dev/null
+++ b/templates/happs-slow-linking-bug.st
@@ -0,0 +1,37 @@
+<h3>HAppS Slow Link Time Workarounds</h3>
+<p>
+The fact that cabal-installing HAppS takes an hour is
+officially a <a
+href="http://code.google.com/p/happs/issues/detail?id=29">bug</a>. Hopefully
+this situation will be remedied as HAppS matures and, eventually, has
+an official release.  
+<p>
+I found this bug pretty problematic when I was experiencing it and I know I'm not the only one. 
+So, I will share some experiences and observations that will hopefully help others,
+and maybe even help diagnose and eventually squash this bug.
+<p>
+First of all, you don't actually need to compile an executable to run a HAppS server, 
+and when you run from inside ghci the link time bug has no effect. So for a while I 
+was doing this, by loading ghci using ./hackInGhci.sh and then running runInGhci inside Main.hs.
+<p>
+Secondly, at some point this problem went away, and my link time dropped from 5-10 minutes to under 10 seconds.
+<p>
+This is definitely due to a change in my own code base, not HAppS repo code, since I am only 
+running against what I cabal installed and not the volatile HAppS library code in darcs.
+At some point I intend to attempt a more precise diagnosis
+by doing binary cuts on my repo and identifying the changes that seem
+to have the biggest impact. I do have some suspicions. 
+<ul>
+  <li>Problems are related to Template Haskell and/or Data.Deriving</li>
+  <li>Splitting up big modules into smaller modules
+      <br>When I saw link times over 5 minutes I tried to isolate the 
+        "slow" methods in a file called "Slow.hs" so that the linking is only slow when that file changes.
+        Lately I removed the Slow module since it didn't seem necessary anymore.</li>
+  <li>Supplying type signatures helps, and the more concrete the type signature the better.
+  <br>So, (askUsers :: Query TutorialState (M.Map String User) ) rather than (askUsers :: MonadReader State m => m (M.Map String User) )
+  <br>tentative idea: ghc -fwarn-missing-signatures and give maximally precise signatures everywhere.</li>
+</ul>
+
+<p>
+
+The shell command ./runServer.sh, which creates an executable and starts the server, also times the compile & link, and rings a bell when it's done. I figure this will be helpful if slow link times creep back in.
diff --git a/templates/header.st b/templates/header.st
--- a/templates/header.st
+++ b/templates/header.st
@@ -1,41 +1,15 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
-  <title> HAppS Tutorial </title>
-  <link rel="stylesheet" href="/static/tutorial.css" type="text/css" />
-</head>
 
-<body>
-
     <div id="header">
+      
       <img src="/static/HAppSTutorialLogo.png" alt="HAppS Tutorial">
-	<a href="http://h-master.net/web2.0/"><font size=1>logo created by the web 2.0 logo generator</font></a
-      <!-- <h1>HAppS Tutorial</h1> -->
-      <h4> <a href="/tutorial/home" class="leftitem">Home</a>
-	   <!-- |<a href="/tutorial/about">About</a>
-	   |<a href="/tutorial/faq">FAQ</a>	   
-	   |<a href="/tutorial/contact">Contact</a> -->
-           |<a href="/tutorial/login">Login</a>
-           |<a href="/view">Logged in as</a>
-           |<a href="/list">View all users</a>
-           <!-- |<a href="/market/">Marketplace</a>
-           |<a href="/market/sendmoney">Send Money Abroad</a> -->
+	<a href="http://h-master.net/web2.0/"><font size=1>logo created by the web 2.0 logo generator</font></a>
+      
+      <h4> 
+            $ menubar() $
+           
+
       </h4>
       <h4>
-	  <!-- {% if userNode %}
-	  Logged in as: {{ userNode.username|escape}}
-	  |<a href="/summary/" class="leftitem">Summary</a>
-	  |<a href="/accounts/">Credit Relationships</a>
-	  |<a href="/payments/">Payments</a>
-	  |<a href="/profile/">Profile</a>
-          |<a href="/inbox/">&nbsp<img src="/site_media/inbox-nomail.png">&nbsp</a>
-	  |<a href="/logout/">Log out</a>
-	  {% else %}
-	  <a href="/login/" class="leftitem">Log in</a>
-	  |<a href="/register/">Sign up</a>	  
-	  {% endif %} -->
           
       </h4>
     </div>
diff --git a/templates/home.st b/templates/home.st
--- a/templates/home.st
+++ b/templates/home.st
@@ -4,21 +4,42 @@
 
 <p>And <a href="http://www.happs.org">HAppS</a> is a great way to build web applications.</p>
 
-$! <p>Unfortunately, the HAppS documentation is sorely lacking.  Without good documentation, even something as trivial as <a href="http://www.google.com/search?hl=en&q=hello+world+happs">hello world</a> can seem to take a Ph.D. in HAppSology.</p>
-
-<p>I created this tutorial to show that this isn't so, and to popularize the use of my favorite language,
-haskell, in web applications. </p> !$
-
 <p>I created this tutorial to popularize the use of my favorite language, haskell, in web applications. </p>
 
-<p>This tutorial is its own demo. For best results, you should <a href="/tutorial/run-tutorial-locally">install and run</a> it in a local environment where you have control. Then, when you are done learning, you can use the tutorial code as a template for your own HAppS applications.</p>
+<p>This tutorial is its own demo. For best results, you should
+<a href="/tutorial/run-tutorial-locally">install and run</a>
+it in a local environment where you have control. Then, when you are done
+learning, you can use the tutorial code as a template for your own
+HAppS applications. 
+</p>
 
 <p>If you use Ruby on Rails, Django, Perl Catalyst, PHP, or some other popular web framework, but
 have programmed in haskell and would like to use the world's greatest language for your next web project,
 this tutorial will give you all the knowledge you need.</p>
 
-$! <p>No Ph.D. required. <sup>&reg</sup></p> !$
+<p>As I just said a second ago,
+the best way to learn how to use use HAppS with this tutorial is to actually <a
+href="/tutorial/run-tutorial-locally">install and run</a> it in a
+local environment.  
 
-<p><a href="/tutorial/prerequisites/">Prerequisites</p>
-<p><a href="/tutorial/start-tutorial">Start The Tutorial.</a></p>
-<p><a href="http://code.haskell.org/happs-examples">Browse The Source</a></p>
+<p>So if you can, do that first.
+
+<p>Getting on with the tutorial proper, our first lesson examines the 
+<a href="/tutorial/main-function">main function</a> in a HAppS program.
+The second lesson explains how to do <a
+href="/tutorial/basic-url-handling">basic url handling</a>.
+The third lesson covers <a href="/tutorial/templates-dont-repeat-yourself">using templates</a>.</p>
+
+<p>More lessons are planned. This is a work in progress. Stay tuned.</p>
+
+$! <p>Lesson 2 is <a href="/tutorial/using-templates">using templates</a</p> !$
+   
+$! <p>Lesson 3 is <a href="/tutorial/managing-state">managing state</a></p> !$
+
+
+
+
+
+
+
+
diff --git a/templates/home_interpersonal.st b/templates/home_interpersonal.st
deleted file mode 100644
--- a/templates/home_interpersonal.st
+++ /dev/null
@@ -1,42 +0,0 @@
-{% extends "base.html" %}
-{% block content %}
-
-
-      <p>RippleDeals is a marketplace where you buy on credit
-      granted by people who trust you. Or you sell on credit, which
-      is guaranteed by people you trust. Credit is used in a
-      person-to-person <a href="/creditpath">credit path</a> which can be many people
-      long.</p><!--
-        <p>Instead of letting the banking system determine your credit, you trust the people in your life w
-	   ho have earned it.</p>-->
-
-      <p>Since RippleDeals doesn't depend on the banking system,
-      you can do deals without using credit cards, writing a check,
-      or handling cash.</p>
-
-      <p>You also have a simple way to start doing business in
-      emerging currencies such as community currencies and digital
-      gold, or even online gaming currencies. Of course, dollars,
-      euro, and other mainstream national currencies are fine
-      too.</p><!--
-
-
-      <p>Since credit flows along a trust chain, where each link has a high degree of confidence in the next,
-	scams that are common in other online marketplaces simply won't work here. </p>
-      -->
-
-      <p>RippleDeals is free.</p>
-
-
-    {% include "dealsearch.html" %}
-
-{% endblock %}
-
-
-
-
-{% block footer %}
-    <!-- users: {{ num_users }}<br>
-    accounts: {{ num_accounts }}<br>
-    payments: {{ num_payments }}<br> -->
-{% endblock %}
diff --git a/templates/leastFavoriteAnimal.st b/templates/leastFavoriteAnimal.st
new file mode 100644
--- /dev/null
+++ b/templates/leastFavoriteAnimal.st
@@ -0,0 +1,11 @@
+
+
+<p>*********** My least favorite animal is $ leastFavoriteAnimal $. 
+
+<p>*********** (set in another template, leastFavoriteAnimal.st) 
+
+<p>*********** Notice that this template file uses CamelCase rather than dashes to separate words.
+   Otherwise there's an error with included templates.
+   So, in general: avoid template file names with dashes or underscores, and just use CamelCase for templates.
+
+
diff --git a/templates/login.st b/templates/login.st
--- a/templates/login.st
+++ b/templates/login.st
@@ -1,22 +1,15 @@
-<div id="create">
-<h1>Register</h1>
-<form action="/newuser" method="post">
-<label>Username:<input type="textfield" name="username"/></label>
-<br/>
-<label>Password:<input type="textfield" name="password"/></label>
-<br/>
-<label>Verify Password:<input type="textfield" name="password2"/></label>
-<br/>
-<input type="submit" name="create" value="Create Account">
-</form>
-</div>
 <div id="login">
-<h1>Log In</h1>
-<form action="/login" method="post">
-<label>Username:<input type="textfield" name="username"/></label>
-<br/>
-<label>Password:<input type="textfield" name="password"/></label>
-<br/>
-<input type="submit" name="create" value="Log in">
-</form>
+    <form action="/tutorial/actions/login" method="post">
+      <table>
+	<tr><td><label>Username:</td> <td><input type="textfield" name="username"/></label></td> </tr>
+ 	
+	<tr> <td><label>Password:</td> <td><input type="password" name="password"/></label> </td> </tr>
+
+	<tr> <td> <input type="submit" name="create" value="Log in"> </td>
+	     <td> <a href="/tutorial/register">register </a></td>
+	</tr>
+      </table>
+    </form>
+    $ errortemplate() $
+
 </div>
diff --git a/templates/menuLoggedIn.st b/templates/menuLoggedIn.st
new file mode 100644
--- /dev/null
+++ b/templates/menuLoggedIn.st
@@ -0,0 +1,2 @@
+<a class = "menuitem" href="/tutorial/actions/logout"> logout $ user $ </a>
+
diff --git a/templates/menubar.st b/templates/menubar.st
new file mode 100644
--- /dev/null
+++ b/templates/menubar.st
@@ -0,0 +1,33 @@
+<table><tr>
+     <td> 
+
+	   <!--
+	   |<a href="/tutorial/about">About</a>
+	   |<a href="/tutorial/faq">FAQ</a>
+	   |<a href="/tutorial/contact">Contact</a>
+	   -->
+       
+            <a class="$ menustyleHome $" href="/tutorial/home" class="leftitem">home</a>
+           |<a class="$ menustyleViewallusers $" href="/tutorial/view-all-users">view all users</a>
+
+           <!-- |<a href="/market/">Marketplace</a>
+           |<a href="/market/sendmoney">Send Money Abroad</a> -->
+
+
+     </td>
+     <td width=500>$! td is for alignment only !$</td>
+     <td> $ userMenu $ </td>
+			
+</tr></table>
+
+
+
+
+
+
+
+           
+
+
+
+
diff --git a/templates/my-favorite-animal.st b/templates/my-favorite-animal.st
new file mode 100644
--- /dev/null
+++ b/templates/my-favorite-animal.st
@@ -0,0 +1,10 @@
+<html>
+  My favorite animal is a: $ favoriteAnimal $ (set with setAttribute)
+  <p>
+  $ leastFavoriteAnimal() $
+  <p>
+  If I forget to set an attribute (favoriteMammal), it just doesn't display: $ favoriteMammal $
+  <p>
+  <p>You can comment out parts of a template: $! This Won't Display !$
+</html>
+
diff --git a/templates/myhomepage.st b/templates/myhomepage.st
deleted file mode 100644
--- a/templates/myhomepage.st
+++ /dev/null
@@ -1,11 +0,0 @@
-<html>
-  This is my homepage.
-  <p>
-  It is generated using HStringTemplate.
-  <p>
-  My favorite animal is a: $ favoriteAnimal $ (set with setAttribute)
-  <p>
-  $ favoriteAnimal() $ 
-  <p>
-  <a href="moreFavoriteAnimals.html">More Favorite Animals</a>
-</html>
diff --git a/templates/newuser.st b/templates/newuser.st
new file mode 100644
--- /dev/null
+++ b/templates/newuser.st
@@ -0,0 +1,1 @@
+User Created: $ newuser $
diff --git a/templates/prerequisites.st b/templates/prerequisites.st
--- a/templates/prerequisites.st
+++ b/templates/prerequisites.st
@@ -14,7 +14,7 @@
    <li>Please let me know -- or patch the tutorial -- if I forgot something. I hate getting stuck on some finicky aspect of installation when I am trying to learn something.</li>
 </ul>
 
-<p><a href="/tutorial/start-tutorial">Get started!</a></p>
+<p><a href="/tutorial/run-tutorial-locally">Install me already!</a></p>
 
 
       
diff --git a/templates/register.st b/templates/register.st
new file mode 100644
--- /dev/null
+++ b/templates/register.st
@@ -0,0 +1,12 @@
+    <form action="/tutorial/actions/newuser" method="post">
+    <label>Username:<input type="textfield" name="username"/></label>
+    <br/>
+    <label>Password:<input type="password" name="password"/></label>
+    <br/>
+    <label>Verify Password:<input type="password" name="password2"/></label>
+    <br/>
+    <input type="submit" name="create" value="Create Account">
+    </form>
+    <font color=red>
+      $ errormsgRegister $
+    </font>
diff --git a/templates/run-tutorial-locally.st b/templates/run-tutorial-locally.st
--- a/templates/run-tutorial-locally.st
+++ b/templates/run-tutorial-locally.st
@@ -2,22 +2,34 @@
 
 <p> Before going further, you may want to inform yourself about the <a href=/tutorial/prerequisites>basic prerequisites</a>, both knowledge and equipment, you need to make the best use of this tutorial </p>
 
-<p>This tutorial is cabalized. You can install and run it simply by doing: sudo cabal install happs-tutorial.  You should then be able to run the resulting binary and view the tutorial offline at http://localhost:5001.</p>
+<p>This tutorial is cabalized. You can install and run it simply by doing 
+<p>cabal install happs-tutorial
 
-<p>The cabal installation may take up to an hour, mainly because the HAppS-Server installation is slow, but it should succeed in one shot. Incidentally, the fact that installing HAppS takes this long is arguably a <a href="http://code.google.com/p/happs/issues/detail?id=29">bug</a>. Hopefully this situation will be remedied as HAppS matures and, eventually, has an official release</p>
+<p>The cabal installation may take up to an hour, mainly because the
+HAppS-Server installation is slow, but it should succeed in one
+shot. This is a symptom of the <a href="/tutorial/happs-slow-linking-bug">HAppS slow linking bug</a>.
 
 <p>If you've never used cabal install or need more detailed info....</p>
 
 <ul>
     <li>Haskell: You need at least ghc 6.8.2 to install HAppS. I installed this with with apt-get install haskell (works for ubuntu hardy heron), and then <a href="http://www.haskell.org/ghc/download.html">upgraded to ghc 6.8.3</a> as this is supposed to have fixed some bugs.</li> 
     <li>Dependency chasing haskell package installers: you should have the latest versions of cabal and cabal install from <a href="http://hackage.haskell.org/packages/archive/pkg-list.html">hackage</a>. These are already included in the latest version of ghc, or they will be soon. Another reason to upgrade to ghc 6.8.3.</li>
-    <li>If you want to check out the latest version of this tutorial, install <a href="http://www.darcs.net">Darcs</a> and check out the repo with darcs get http://code.haskell.org/happs-examples</li>
-    <li>cabal installs the tutorial at /home/yourdir/.cabal/bin/happs-tutorial. In practice, I usually recompile and run changed code by executing ./runServer.sh, in the top project directory.</li>
-  <li>You should now be able to browse this tutorial offline by running the executable, and opening http://localhost:5001 in your browser.</li>
-  <li>You may also want to <a href="start-happs-on-boot">start HAppS on boot</a>.</li>
-  </ul>
+    <li>If you want to check out the latest version of this tutorial, install <a href="http://www.darcs.net">Darcs</a> and check out the repo with darcs get http://code.haskell.org/happs-tutorial</li>
+</ul>
 
-<p><a href="/tutorial/start-tutorial">Get started!</a></p>
+<p>To run the app, either do ./hackInGhci.sh and then execute runInGhci inside Main.hs, or recompile
+   the executable using ./runServerWithCompileNLink.sh.
+   Really you only need to be inside ghci if you are experiencing
+   the <a href="/tutorial/happs-slow-linking-bug">slow link time issue</a>.
+   This isn't a problem at time of writing but seems to crop up from time to time.
+<p>
+Shutdown with ctrl-c.
+<p>
+You should now be able to browse this tutorial offline by running the executable, and opening http://localhost:5001 in your browser.
+<p>
+You may also want to <a href="start-happs-on-boot">start HAppS on boot</a>.
+
+<p>Next up is the <a href="/tutorial/main-function">HAppS server main function</a>.</p>
 
 
 
diff --git a/templates/start-happs-on-boot.st b/templates/start-happs-on-boot.st
--- a/templates/start-happs-on-boot.st
+++ b/templates/start-happs-on-boot.st
@@ -2,17 +2,25 @@
 
 <p>What happens if your HAppS deployment server experiences a power outage?</p>
 
-<p>The following instructions are one way to get your HAppS application to start up automatially when the machine is booted.</p>
-
-<p>cp /etc/init.d/ssh /etc/init.d/happs-app</p>
-
-<p>edit that to do the right thing with Main.exe executable.</p>
-
-<p>install it into the linux init with</p>
-
-<p>sudo update-rc.d happs-app multiuser</p>
-
-<p>this is all 
+<p>Or what if the HAppS process just dies for
+<a href="http://code.google.com/p/happs/issues/detail?id=40">mysterious reasons?</a>
 
+<p>The way I deal with this both these issues with a public-facing happs application is to have a cron job that runs every minute, that will start the happs application if it isn't running.</p>
 
-<p>These instructions are valid (at least) for debian/ubuntu, loosely following instructions at the <a href="http://www.debian.org/doc/debian-policy/ch-opersys.html#s9.3.3">debian policy manual</a>.</p>
+<p>
+  thartman@thartman-laptop:~/happs-tutorial>crontab -l
+<br>* * * * *   /home/thartman/happs-tutorial/happs-tutorial.cron.sh
+<br>
+<br>thartman@thartman-laptop:~/happs-tutorial>cat happs-tutorial.cron.sh
+<br># this is a workaround to a problem that my happs app dies for reasons described at
+<br># http://code.google.com/p/happs/issues/detail?id=40
+<br># generate the executable first by running runServer.sh
+<br># then add this file to your crontab so you have something like
+<br># thartman@thartman-laptop:~>crontab -l
+<br># * * * * *   /home/thartman/happs-tutorial/happs-tutorial.cron.sh
+<br>
+<br>if [ -z "`pgrep happs-tutorial`" ];
+<br>  then cd ~/happs-tutorial
+<br>          ./happs-tutorial >happs-tutorial.cron.out 2>happs-tutorial.cron.err
+<br>fi
+</p>
diff --git a/templates/start-tutorial.st b/templates/start-tutorial.st
deleted file mode 100644
--- a/templates/start-tutorial.st
+++ /dev/null
@@ -1,25 +0,0 @@
-<h3>Get Started Learning HAppS</h3>
-
-<p>Like the <a href="/tutorial/home">home</a> page says, the best way to learn how to use use HAppS with this tutorial is to actually <a href="/tutorial/run-tutorial-locally">install and run</a> it in a local environment.</p>
-
-<p>So, step 1 is to <a href="/tutorial/run-tutorial-locally">install and run this tutorial locally</a></p>
-
-<p>Getting on with the tutorial proper, our first lesson examines the <a href="/tutorial/main-function">main function</a> in a HAppS program.
-
-<p>The second lesson explains how to do <a href="/tutorial/basic-url-handling">basic url handling</a>.</p>
-
-<p>The third lesson covers <a href="/tutorial/using-templates">using templates</a>.</p>
-
-<p>More lessons are planned. This is a work in progress. Stay tuned.</p>
-
-$! <p>Lesson 2 is <a href="/tutorial/using-templates">using templates</a</p> !$
-   
-$! <p>Lesson 3 is <a href="/tutorial/managing-state">managing state</a></p> !$
-
-
-
-
-
-
-
-
diff --git a/templates/stringtemplate-basics.st b/templates/stringtemplate-basics.st
new file mode 100644
--- /dev/null
+++ b/templates/stringtemplate-basics.st
@@ -0,0 +1,44 @@
+<h3>StringTemplate Basics</h3>
+
+<p>In the previous section we rendered a template in ghci using the following command
+
+<p>*Main Misc View Text.StringTemplate> do templates <- directoryGroup "templates" ; writeFile "output.html" ( renderTemplateGroup templates [] "templates-dont-repeat-yourself" ) 
+
+<p>Let's look more carefully at these functions.
+
+<ul>
+  <li>The directoryGroup function reads in all *.st type files in a directory,
+      and returns an IO STGroup value, which is basically a group
+      of StringTemplates.
+      <br>*Main Misc View Text.StringTemplate> :t (directoryGroup :: String -> IO (STGroup String))
+      <br>The actual type of directoryGroup is a little less concrete than the above, and uses type classes.
+      <br>Our :t command gives directoryGroup a concrete type, and since there's no error, we know it typechecks.
+  <li>renderTemplateGroup takes an STGroup, some template key/value pairs, and a named template, and renders
+      the template if it is found in the STGroup. If it is not found, an error is returned.
+      <br>*Main Misc View Text.StringTemplate> :t renderTemplateGroup
+      <br>renderTemplateGroup :: STGroup String -> [(String, String)] -> String -> String
+</ul>
+
+<p>Next, let's look at a slightly more involved example of StringTemplate usage than we've seen so far.
+
+<ul>
+  <li>The controller: myFavoriteAnimal, in <a href="/src/ControllerBasic.hs">src/ControllerBasic.hs</a>
+      <br>a snip: <br> &nbsp; renderTemplateGroup templates
+                  <br> &nbsp; &nbsp; [("favoriteAnimal", "Tyrannasaurus Rex")
+                                                           , ("leastFavoriteAnimal","Bambi")]
+                                                    \$ "my-favorite-animal" 
+  <li>The rendered page: <a href="/usingtemplates/my-favorite-animal">my favorite animal</a>
+  <li>The template: <a href="/templates/my-favorite-animal.st">templates/my-favorite-animal.st</a>
+  <li>An included template: <a href="/templates/leastFavoriteAnimal.st">leastFavoriteAnimal()</a>
+</ul>
+
+<p> Try to gain an understanding of the most important features in the StringTemplate system
+    by getting a sense of how the my-favorite-animal page got generated. </p>
+
+<p> When you're done doing that, you should have enough StringTemplate knowledge to shoot yourself in the foot :)
+
+<p> For a more in depth look at StringTemplate, see the following:
+
+<ul><li>blee
+    <li>bleh
+</ul>
diff --git a/templates/tableofcontents.st b/templates/tableofcontents.st
new file mode 100644
--- /dev/null
+++ b/templates/tableofcontents.st
@@ -0,0 +1,14 @@
+
+<ul>
+  <li><a class="$ menustyleHome $" href="/tutorial/home/">happs intro</a>
+  <li><a class="$ menustylePrerequisites$" href="/tutorial/prerequisites/">prerequisites</a>
+  <li><a class="$ menustyleRuntutoriallocally $" href="/tutorial/run-tutorial-locally">happs install</a>
+  <li><a class="$ menustyleMainfunction $" href="/tutorial/main-function">main</a>
+  <li><a class="$ menustyleBasicurlhandling $" href="/tutorial/basic-url-handling">happs url handling</a>
+  <li><a class="$ menustyleTemplatesdontrepeatyourself $"
+         href="/tutorial/templates-dont-repeat-yourself">happs templates</a>
+  <li><a class="$ menustyleStringtemplatebasics $" href="/tutorial/stringtemplate-basics">stringtemplate basics</a>
+
+  <li><a class="$ menustyleStarthappsonboot $" href="/tutorial/start-happs-on-boot">start happs automatically</a
+</ul>
+
diff --git a/templates/templates-dont-repeat-yourself.st b/templates/templates-dont-repeat-yourself.st
new file mode 100644
--- /dev/null
+++ b/templates/templates-dont-repeat-yourself.st
@@ -0,0 +1,69 @@
+<h3>Templates -- So You Don't Repeat Yourself</h3>
+
+<p>Every page in this tutorial has certain things in common -- the header and menu bar for example.
+You wouldn't want to have have to change the menu bar on every single page if there was a new menu item.
+
+<p>This is why you need a templating system.</p>
+
+<p>HAppS doesn't care much what templating system you use.  I use the
+<a href="">TK HStringTemplate</a> package to get the job done, so
+that's the syntax you'll be seeing in what follows. </p>
+
+<p>
+A templating system also helps you individualize output.
+The way this works is by inserting variable text into placeholder templates.
+For instance, the menu bar in this tutorial displays "logout your_username" if you are logged in,
+rather than the login/register options. 
+The line below does this too, just for teaching purposes. If you are logged in, it will display your username.
+</p>
+
+<p> Logged In? Let's see: $ loggedInUser $ </p>
+
+<p>Have a look at the <a href="/templates/templates-dont-repeat-yourself.st">template responsible for the content pane of this page</a>. It's pretty boring, except the line above reads as
+
+<p> &quot; Logged In? Let's see: \$ loggedInUser \$ &quot;
+
+<p>Now, if you are running this tutorial locally, load up ghci by running ./hackInGhci</p>
+
+<p>You can see the effect of
+rendering the current content pane by calling
+
+<p> *Main> :m +Misc View Text.StringTemplate
+
+<br>*Main Misc View Text.StringTemplate> do templates <- directoryGroup "templates" ; writeFile "output.html" \$ renderTemplateGroup templates [] "templates-dont-repeat-yourself" 
+
+<p>and then opening the file output.html in firefox. (On ubuntu, in ghci, I just do ":! firefox output.html &" and the file opens in a new tab in firefox.)
+
+<p>To see how this page would look if you were logged in: 
+
+<p>*Main Misc View Text.StringTemplate> do templates <- directoryGroup "templates" ; writeFile "output.html" \$ renderTemplateGroup templates [("loggedInUser","DarthVader")] "templates-dont-repeat-yourself" 
+
+<p>and reopen output.html in your browser.
+
+<p>As you may have noticed, the html written by the above command is only the current content pane, not the header or table of content links. To render the full page from ghci, as it would appear for a logged in user, you can do 
+
+<p>*Main Misc View Text.StringTemplate> do html <- tutlayout  [("loggedInUser","DarthVader")] "templates-dont-repeat-yourself"; writeFile "output.html" html
+
+<p>If you reload output.htlm, you'll see you are missing the header image and css because you're opening a plain html file
+rather than a page being served by happs (which knows where to find the images and css),
+but other than that the layout is complete.
+
+<p>You can get a sense for how this all works by looking at the tutlayout function in <a href="/src/View.hs">src/View.hs</a>.
+
+<p>It's not too much fun to develop a web page by outputting a string to a static file and then opening 
+it in a browser every time something changes, so the next thing you might want to try is actually
+modifying the current template (in ./templates/templates-dont-repeat-yourself.st) with some random text,
+reloading this actual page, and watching your changes appear.
+
+$!
+<p>You might have also noticed that the table of contents-style navigation links in the left pane
+change colors depending on what page is selected. You could have a look at the the
+<a href="/templates/tableofcontents.st">/templates/tableofcontents.st</a> to get another taste of how templating works.
+Here, HAppS looks at each request to determine what the page was called. 
+If the page matches anything in a certain list, the link class gets set to an "active" value, otherwise it
+gets a default value. 
+!$
+
+<p> We'll learn some <a href="/tutorial/stringtemplate-basics">StringTemplate basics</a> next.</p>
+
+
diff --git a/templates/using-templates.st b/templates/using-templates.st
deleted file mode 100644
--- a/templates/using-templates.st
+++ /dev/null
@@ -1,3 +0,0 @@
-<ul>
-  <li><a href="/usingtemplates/testtgio">my favorite animal</li></li>
-</ul>
diff --git a/templates/view-all-users.st b/templates/view-all-users.st
new file mode 100644
--- /dev/null
+++ b/templates/view-all-users.st
@@ -0,0 +1,1 @@
+Users: $ userList $
