diff --git a/changelog.markdown b/changelog.markdown
--- a/changelog.markdown
+++ b/changelog.markdown
@@ -1,3 +1,10 @@
+2008.10.27
+-----------
+
+### Feature
+
+* Customizable footer
+
 2008.10.26
 -----------
 
diff --git a/panda.cabal b/panda.cabal
--- a/panda.cabal
+++ b/panda.cabal
@@ -1,5 +1,5 @@
 Name:                 panda
-Version:              2008.10.26
+Version:              2008.10.27
 Build-type:           Simple
 Synopsis:             A simple static blog engine
 Description:          A simple static blog engine
@@ -14,9 +14,11 @@
 data-files:			  readme.markdown, changelog.markdown
 
 library
-  build-depends: base, cgi, network, haskell98, old-locale, old-time, directory, filepath, containers, mps >= 2008.10.15, parsedate >= 3000.0.0, rss >= 3000.0.1, xhtml, kibro >= 0.4.1, utf8-string >= 0.3.1, pandoc >= 0.46, MissingH, parsec >= 2, gravatar >= 0.3
+  build-depends: base, cgi, network, haskell98, old-locale, old-time, directory, filepath, containers, mps >= 2008.10.25, parsedate >= 3000.0.0, rss >= 3000.0.1, xhtml, kibro >= 0.4.1, utf8-string >= 0.3.1, pandoc >= 0.46, MissingH, parsec >= 2, gravatar >= 0.3, data-default >= 0.2
   hs-source-dirs: src/
-  exposed-modules:  Panda
+  exposed-modules:  
+                    Main
+                    
                     Panda.Config.Global
 
                     Panda.Controller.Application
@@ -32,12 +34,13 @@
                     Panda.Model.Static
                     Panda.Model.Tag
                     
+                    Panda.Type.Extension
                     Panda.Type.Pager
                     Panda.Type.Reader
-                    Panda.Type.Sidebar
                     Panda.Type.State
+                    Panda.Type.StaticWidget
                     Panda.Type.Theme
-                    Panda.Type.Extension
+
                     
                     Panda.View.Atom.Comment
                     Panda.View.Atom.Post
@@ -51,16 +54,15 @@
                     Panda.View.Control.Static
                     Panda.View.Control.Tag
                     
-                    Panda.View.Widget.Helper
                     Panda.View.Widget.Body
                     Panda.View.Widget.Footer
                     Panda.View.Widget.Head
                     Panda.View.Widget.Header
+                    Panda.View.Widget.Helper
                     Panda.View.Widget.Navigation
                     Panda.View.Widget.RSS
                     Panda.View.Widget.SearchBar
                     Panda.View.Widget.Sidebar
                     Panda.View.Widget.Template
-                    
-                    Main
-                    
+
+                    Panda
diff --git a/readme.markdown b/readme.markdown
--- a/readme.markdown
+++ b/readme.markdown
@@ -1,4 +1,4 @@
 ## Panda: a simple blog engine in Haskell
 
 * [Panda homepage](http://www.haskell.org/haskellwiki/Panda)
-* [doc](doc/readme)
+* Documentation: inside `doc`
diff --git a/src/Panda/Config/Global.hs b/src/Panda/Config/Global.hs
--- a/src/Panda/Config/Global.hs
+++ b/src/Panda/Config/Global.hs
@@ -8,70 +8,105 @@
 import Control.Arrow ((>>>), (&&&), (***))
 import Data.Maybe
 import System.Directory
+import Data.Default
 
 import Panda.Type.Reader
-import Panda.Type.Sidebar
-import Panda.Type.Theme
+import Panda.Type.StaticWidget
+import Panda.Type.Theme ( to_theme )
 import Panda.Type.Extension
 
-db_id       = "db"
-flat_id     = "."
-post_id     = "blog"
-config_id   = "config"
-tag_id      = "tag"
-comment_id  = "comment"
-sidebar_id  = "sidebar"
-theme_id    = "theme"
 
-db_uri      = db_id
-flat_uri    = db_uri / flat_id
+db_id          = "db"
+flat_id        = "."
+post_id        = "blog"
+config_id      = "config"
+tag_id         = "tag"
+comment_id     = "comment"
+sidebar_id     = "sidebar"
+theme_id       = "theme"
+config_file_id = "site.txt"
 
-config_uri  = flat_uri / config_id / "site.txt"
-sidebar_uri = flat_uri / config_id / sidebar_id
-post_uri    = flat_uri / post_id
-tag_uri     = flat_uri / tag_id
-comment_uri = flat_uri / comment_id
-theme_uri   = flat_uri / config_id / theme_id
+db_uri         = db_id
+flat_uri       = db_uri / flat_id
 
+config_uri     = flat_uri / config_id / config_file_id
+sidebar_uri    = flat_uri / config_id / sidebar_id
+footer_uri     = flat_uri / config_id
+post_uri       = flat_uri / post_id
+tag_uri        = flat_uri / tag_id
+comment_uri    = flat_uri / comment_id
+theme_uri      = flat_uri / config_id / theme_id
 
+data ConfigData = 
+    BlogTitle
+  | BlogSubtitle
+  | HostName
+  | AuthorEmail
+  | PerPage
+  | Navigation
+  | Root
+  | Sidebar
+  | Footer
+  | Favicon
+  | AnalyticsAccountId
+  | Extensions
+  | Theme
+  | PostDateFormat
+  | CommentDateFormat
+  | UrlDateFormat
+  | UrlDateMatcher
+  | UrlTitleSubs
+  | UrlDateTitleSeperator
+  | Cut
+  | SummaryForRoot
+  | SummaryForTag
+  | SummaryForRss
+  deriving (Show)
+  
 -- unsafe, must restart server after changing config file, sorry about that ...
 -- but these configs are read only, and keep the view pure, so no monad headaches involved.
 
-user_config = parse_config config_uri
+user_config   = parse_config config_uri
+for' x d      = user_config.lookup (x.show_data) .fromMaybe d
+for_int' x d  = for' x d .read :: Int
+for_list' x d = for' x d .parse_list
+for x         = for' x (x.show_data)
 
-config_for' s d = user_config.lookup s .fromMaybe d
-config_for s    = config_for' s s
+blog_title    = for BlogTitle
+blog_subtitle = for BlogSubtitle
+host_name     = for HostName
+author_email  = for AuthorEmail
 
-blog_title      = config_for "blog_title"
-blog_subtitle   = config_for "blog_subtitle"
-host_name       = config_for "host_name"
-author_email    = config_for "author_email" 
+per_page      = for_int' PerPage "7"
+navigation    = for_list' Navigation "About" .("Home" :)
 
-per_page        = config_for' "per_page" "7" .read :: Int
-navigation      = config_for' "navigation" "About" .parse_list.("Home" :)
+panda_url     = "http://www.haskell.org/haskellwiki/Panda"
 
-panda_url       = "http://github.com/nfjinjing/panda"
 root            
   | user_root.belongs_to ["/", ""]  = "/"
   | otherwise                       =  user_root.("/" /).remove_trailing_slash
-  where user_root = config_for' "root" "/"
+  where user_root = for' Root "/"
 
-default_reader  = Markdown
+default_reader  = def
 
-sidebar = config_for "sidebar" .parse_list .map (sidebar_uri /).select (to_utf8 >>> doesFileExist >>> purify )
-  .map (read_sidebar_item default_reader >>> purify)
-  
-favicon = config_for' "favicon" "/favicon.ico"
+load_widget = read_static_widget default_reader >>> purify
+sidebar = for_list' Sidebar "" .map (sidebar_uri /).select (to_utf8 >>> doesFileExist >>> purify )
+  .map load_widget
 
+footer  = for Footer 
+  .(footer_uri / ) 
+  .(\x -> if x.to_utf8.doesFileExist.purify then Just $ load_widget x else Nothing)
+  
+favicon = for' Favicon "/favicon.ico"
 
 -- extensions
-analytics_account_id = config_for "analytics_account_id"
-extensions = config_for' "extensions" "search, comment, analytics" .parse_list .to_extensions
+analytics_account_id = for AnalyticsAccountId
+extensions           = for_list' Extensions "search, comment, analytics" .read_data_list :: [Extension]
 
 -- theme
-default_theme = blank_theme
-user_theme_name = config_for "theme"
-user_theme_uri = (theme_uri / user_theme_name) ++ ".txt"
+default_theme   = def
+user_theme_name = for Theme
+user_theme_uri  = (theme_uri / user_theme_name) ++ ".txt"
 
 theme = if user_theme_uri.doesFileExist.purify
   then parse_config user_theme_uri .(("name", user_theme_name) : ) .to_theme
@@ -79,19 +114,19 @@
   
 -- custom
 as_l s                   = "[" ++ s ++ "]"
-post_date_format         = config_for' "post_date_format" "%y-%m-%d"
-comment_date_format      = config_for' "comment_date_format" "%y-%m-%d %T"
-url_date_format          = config_for' "url_date_format" "%y-%m-%d"
-url_date_matcher         = config_for' "url_date_matcher" "\\d{2}-\\d{2}-\\d{2}"
-url_title_subs           = config_for' "url_title_subs" "" .as_l .read :: [(String, String)]
-url_date_title_seperator = config_for' "url_date_title_seperator" " "
+post_date_format         = for' PostDateFormat "%y-%m-%d"
+comment_date_format      = for' CommentDateFormat "%y-%m-%d %T"
+url_date_format          = for' UrlDateFormat "%y-%m-%d"
+url_date_matcher         = for' UrlDateMatcher "\\d{2}-\\d{2}-\\d{2}"
+url_title_subs           = for' UrlTitleSubs "" .as_l .read :: [(String, String)]
+url_date_title_seperator = for' UrlDateTitleSeperator " "
 
 -- summary
-cut              = config_for' "cut" "✂-----" .to_utf8
+cut              = for' Cut "✂-----" .to_utf8
 parse_boolean    = belongs_to ["true", "1", "y", "yes", "yeah"]
-summary_for_root = config_for "summary_for_root" .parse_boolean
-summary_for_tag  = config_for "summary_for_tag"  .parse_boolean
-summary_for_rss  = config_for "summary_for_rss"  .parse_boolean
+summary_for_root = for SummaryForRoot .parse_boolean
+summary_for_tag  = for SummaryForTag  .parse_boolean
+summary_for_rss  = for SummaryForRss  .parse_boolean
 
 
 
diff --git a/src/Panda/Controller/Application.hs b/src/Panda/Controller/Application.hs
--- a/src/Panda/Controller/Application.hs
+++ b/src/Panda/Controller/Application.hs
@@ -13,7 +13,7 @@
 
 -- env
 import Panda.Helper.Env hiding (tag, uri)
-import Panda.Helper.StateHelper
+import Panda.Helper.StateHelper hiding (only_for)
 import Prelude hiding ((.), (/), (^), id)
 import qualified Panda.Type.State as S
 import qualified Panda.Config.Global as G
@@ -36,42 +36,39 @@
 
 -- helpers
 -- liftIO: move to an (u)pper level monad
-u = liftIO
-blog_regex = G.url_date_matcher
-
-init_post tags x = do
-  x.Tag.fill_tag tags.Comment.fill_comment_size.u
-
-tag_list = Tag.list.u
+u                = liftIO
+blog_regex       = G.url_date_matcher
+init_post tags x = x.Tag.fill_tag tags.Comment.fill_comment_size.u
+tag_list         = Tag.list.u
 
 
 -- main controller
 
 pages = 
-  [ ("$"                  ,index              )
-  , ("(\\?.+)?$"          ,index              )
-  , ("rss.xml$"           ,index_feed         )
-  , (blog_regex           ,blog               )
-  , ("static/."           ,static             )
-  , ("tag/.*/rss.xml$"    ,tag_feed           )
-  , ("tag/."              ,tag                )
-  , ("search"             ,route_for_extension Search   $ search             )
-  , ("comment/create"     ,route_for_extension Comment  $ comment_create     )
+  [ ("$"                  ,index                                  )
+  , ("(\\?.+)?$"          ,index                                  )
+  , ("rss.xml$"           ,index_feed                             )
+  , (blog_regex           ,blog                                   )
+  , ("static/."           ,static                                 )
+  , ("tag/.*/rss.xml$"    ,tag_feed                               )
+  , ("tag/."              ,tag                                    )
+  , ("search"             ,only_for Search   $ search             )
+  , ("comment/create"     ,only_for Comment  $ comment_create     )
   ] .map_fst ((G.root /) >>> ("^" ++))
   ++
-  [ ("^" ++ G.root ++ "$" ,index              )
-  , ("^" ++ G.root ++ "?" ,index              )
+  [ ("^" ++ G.root ++ "$" ,index                                  )
+  , ("^" ++ G.root ++ "?" ,index                                  )
   ]
   
 
-route_for_extension ext x = if has_extension ext then x else not_found
+only_for ext x = if has_extension ext then x else not_found
 
 index = do
   posts <- Post.list.u
   p <- paginate posts
   tags <- tag_list
   let nav = if p.Pager.current == 1 then home_nav else no_navigation
-  let state = S.empty { S.uid = G.post_id, S.pager = p, S.tags = tags, S.nav_location = nav }
+  let state = def { S.uid = G.post_id, S.pager = p, S.tags = tags, S.nav_location = nav }
   
   posts.mapM (init_post tags) ^ PostV.list state >>= output_html
 
@@ -86,7 +83,7 @@
   tags <- tag_list
   
   test_data <- S.mk_human_test .u
-  let state = S.empty { S.uid = id, S.tags = tags, S.resource_title = blog.resource_title, S.human_test_data = test_data }
+  let state = def { S.uid = id, S.tags = tags, S.resource_title = blog.resource_title, S.human_test_data = test_data }
   blog.(init_post tags) ^ PostV.view state comments >>= output_html
 
 
@@ -97,7 +94,7 @@
   
   let nav_id = static_page.Static.uid.id_to_resource
   let nav   = if nav_id.belongs_to G.navigation then nav_id else no_navigation
-  let state = S.empty { S.uid = id, S.tags = tags, S.nav_location = nav, S.resource_title = static_page.resource_title }
+  let state = def { S.uid = id, S.tags = tags, S.nav_location = nav, S.resource_title = static_page.resource_title }
   StaticV.view state static_page .output_html
 
 tag = do
@@ -109,7 +106,7 @@
     Just post_set -> do
       posts <- post_set.to_list.rsort.mapM (Post.get) .u >>= mapM (init_post tags)
       p <- paginate posts
-      let state = S.empty { S.uid = id, S.pager = p, S.tags = tags, S.resource_title = tag_name.Tag.resource_title_from_name }
+      let state = def { S.uid = id, S.pager = p, S.tags = tags, S.resource_title = tag_name.Tag.resource_title_from_name }
       posts.TagV.view state.output_html
 
 tag_feed = do
@@ -129,7 +126,7 @@
   p <- paginate posts
   tags <- tag_list
   query <- uri
-  let state = S.empty { S.uid = query, S.pager = p, S.tags = tags, S.resource_title = query }
+  let state = def { S.uid = query, S.pager = p, S.tags = tags, S.resource_title = query }
 
   posts.mapM (init_post tags) >>= \x -> x.SearchV.view state s.output_html
 
@@ -149,20 +146,19 @@
 get_input_data = show_data >>> get_input
 
 check_human = do
-  x <- [Comment.LeftNumber, Comment.RightNumber, Comment.Operator, Comment.HumanHack].mapM get_input_data ^ map fromJust
-  let [l, r, op, h] = x
+  [l, r, op, h] <- [Comment.LeftNumber, Comment.RightNumber, Comment.Operator, Comment.HumanHack].mapM get_input_data ^ map fromJust
   return $ S.simple_eval (l.read) (r.read) (op.S.read_op) .is (h.read)
 
 -- create helper, should be refactored to some common aspect
 check_create =
-  [ validate Comment.Author     ( length >>> (> 0))
-  , validate Comment.AuthorLink ( const True)
-  , validate Comment.Body       ( length >>> (> 0))
-  , validate Comment.EmptyField ( empty )
-  , validate Comment.LeftNumber ( belongs_to (S.nums.map show))
-  , validate Comment.RightNumber ( belongs_to (S.nums.map show))
-  , validate Comment.Operator ( belongs_to (S.ops.map S.display_op))
-  , validate Comment.HumanHack ( belongs_to (S.nums.map show))
+  [ validate Comment.Author       ( length >>> (> 0))
+  , validate Comment.AuthorLink   ( const True)
+  , validate Comment.Body         ( length >>> (> 0))
+  , validate Comment.EmptyField   ( empty )
+  , validate Comment.LeftNumber   ( belongs_to (S.nums.map show))
+  , validate Comment.RightNumber  ( belongs_to (S.nums.map show))
+  , validate Comment.Operator     ( belongs_to (S.ops.map S.display_op))
+  , validate Comment.HumanHack    ( belongs_to (S.nums.map show))
   , check_human
   ] .sequence ^ and
 
@@ -171,4 +167,4 @@
   maybe_s <- get_input_data s
   case maybe_s of
     Nothing -> return False
-    Just v -> return $ f v
+    Just v  -> return $ f v
diff --git a/src/Panda/Helper/Env.hs b/src/Panda/Helper/Env.hs
--- a/src/Panda/Helper/Env.hs
+++ b/src/Panda/Helper/Env.hs
@@ -18,6 +18,7 @@
   , module System.Time
   , module System.Directory
   , module Data.Foldable
+  , module Data.Default
 ) where
   
 import MPS hiding (base, col, sub, date)
@@ -36,3 +37,4 @@
 import System.Time
 import System.Directory
 import Data.Foldable (find)
+import Data.Default
diff --git a/src/Panda/Helper/Helper.hs b/src/Panda/Helper/Helper.hs
--- a/src/Panda/Helper/Helper.hs
+++ b/src/Panda/Helper/Helper.hs
@@ -14,7 +14,7 @@
 import Text.XHtml.Strict
 import Control.Monad hiding (join)
 import Data.Maybe
-import Panda.Type.Pager as Pager hiding (empty)
+import Panda.Type.Pager as Pager
 import MPS hiding (date)
 import Prelude hiding ((.), (/), (^), id, readFile, writeFile)
 import Char
@@ -23,14 +23,12 @@
 import Panda.Type.Reader
 import System.FilePath.Posix hiding ((<.>))
 import System.Time
+import Data.Default
 
 
 (/) = (</>)
 infixl 5 /
 
-(^) = (<.>)
-infixl 9 ^
-
 -- global
 parse_config_io s = readFile s ^ (\x -> x.filter_comment.lines.map strip .map (split "\\s*=\\s*") .map fill_snd_blank .map tuple2)
   where fill_snd_blank [x] = [x,""]
@@ -106,18 +104,7 @@
 
 
 -- generic
-
-starts_with _ [] = False
-starts_with (x:xs) (y:ys) | x == y = starts_with xs ys
-                          | otherwise = False
-
-ends_with x y = starts_with (x.reverse) (y.reverse)
-
-capitalize (x:xs) = [x].upper ++ xs.lower
-camel_case = split "_" >>> map capitalize >>> join'
-snake_case = gsub "\\B[A-Z]" "_\\&" >>> lower
 show_data = show >>> snake_case
- 
 
 -- class
 class DataRenderer a where
@@ -134,5 +121,3 @@
 
 class Addressable a where
     uri :: a -> String
-
- 
diff --git a/src/Panda/Helper/StateHelper.hs b/src/Panda/Helper/StateHelper.hs
--- a/src/Panda/Helper/StateHelper.hs
+++ b/src/Panda/Helper/StateHelper.hs
@@ -34,7 +34,7 @@
 default_parse_date s = s.parse_post_date .fromMaybe default_date
 
 has_extension x = G.extensions.has x
-for_extension ext x = if has_extension ext then x else toHtml ""
+only_for ext x = if has_extension ext then x else toHtml ""
 
 -- controller
 paginate = length >>> full_paginate (G.per_page)
diff --git a/src/Panda/Model/Comment.hs b/src/Panda/Model/Comment.hs
--- a/src/Panda/Model/Comment.hs
+++ b/src/Panda/Model/Comment.hs
@@ -44,6 +44,8 @@
 instance Datable Comment where
   date x  = x.uid.split "/".last.default_parse_date
 
+instance Default Comment where
+  def = Comment def def def def def
 
 -- CRUD
 list_for post_id = do
@@ -96,7 +98,7 @@
   write_config_io (uid ++ ".meta") meta
 
 -- extra
-from_post_id x = Comment (post_id_to_uid x) "" "" "" ""
+from_post_id x = def { uid = post_id_to_uid x }
 
 post_id_to_uid x = G.flat_uri / G.comment_id / x.split "/" .last
 uid_to_post_id x = G.post_id / x.split "/" .last
@@ -106,4 +108,4 @@
   return $ x { Post.comment_size = size }
 
 gravatar_default_size = size 40
-gravatar_link x       = gravatarWith (x.author_email) Nothing gravatar_default_size Nothing
+gravatar_link x       = gravatarWith (x.author_email) def gravatar_default_size def
diff --git a/src/Panda/Type/Extension.hs b/src/Panda/Type/Extension.hs
--- a/src/Panda/Type/Extension.hs
+++ b/src/Panda/Type/Extension.hs
@@ -11,6 +11,6 @@
   deriving (Show, Read, Eq)
 
 
-to_extension s   = s.camel_case.read :: Extension
-to_extensions xs = xs.map to_extension
+read_data s   = s.camel_case.read
+read_data_list xs = xs.map read_data
 
diff --git a/src/Panda/Type/Pager.hs b/src/Panda/Type/Pager.hs
--- a/src/Panda/Type/Pager.hs
+++ b/src/Panda/Type/Pager.hs
@@ -1,5 +1,7 @@
 module Panda.Type.Pager where
-  
+
+import Data.Default
+
 data Pager = Pager {
   length :: Int,
   current :: Int,
@@ -9,5 +11,9 @@
   previous :: Int
   }
   deriving (Eq, Show)
+
+instance Default Bool where
+  def = False
   
-empty = Pager 0 0 False False 0 0
+instance Default Pager where
+  def = Pager def def def def def def
diff --git a/src/Panda/Type/Reader.hs b/src/Panda/Type/Reader.hs
--- a/src/Panda/Type/Reader.hs
+++ b/src/Panda/Type/Reader.hs
@@ -8,9 +8,12 @@
 import Text.Pandoc
 import Control.Arrow ((>>>))
 import Text.XHtml.Strict
-import Data.Generics
+import Data.Default
 
-data Reader = Markdown | RST | HTML | Latex deriving (Show, Eq, Typeable, Data)
+data Reader = Markdown | RST | HTML | Latex deriving (Show, Eq)
+
+instance Default Reader where
+  def = Markdown
 
 readers = 
   [ (Markdown,  ["markdown", "md"])
diff --git a/src/Panda/Type/Sidebar.hs b/src/Panda/Type/Sidebar.hs
deleted file mode 100644
--- a/src/Panda/Type/Sidebar.hs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Panda.Type.Sidebar where
-
-import Panda.Helper.Env hiding (body)
-import Prelude hiding ((.), (/), (^), id, readFile)
-import Panda.Type.Reader
-
-data SidebarItem = SidebarItem
-  { name :: String
-  , body :: String
-  , reader :: Reader
-  }
-  deriving (Show, Eq)
-
-instance Markable SidebarItem where
-  markup x  = render_to_html (x.reader) (x.body)
-
-read_sidebar_item default_reader s = liftM2 (SidebarItem name) body (return reader) where
-  body = s.to_utf8.readFile
-  reader = s.take_extension.guess_reader.fromMaybe default_reader
-  name = s.takeFileName.dropExtension
diff --git a/src/Panda/Type/State.hs b/src/Panda/Type/State.hs
--- a/src/Panda/Type/State.hs
+++ b/src/Panda/Type/State.hs
@@ -7,6 +7,7 @@
 import Control.Arrow ((>>>), (&&&), (***))
 import MPS
 import Prelude hiding ((.), (/), (^), id, readFile, writeFile)
+import Data.Default
 
 data State = State
   -- model state
@@ -33,19 +34,22 @@
 display_op Minus = "-"
 
 data HumanTestData = HumanTestData 
-  { left :: Int
+  { left  :: Int
   , right :: Int
-  , op :: Op
+  , op    :: Op
   } deriving (Show)
 
+instance Default HumanTestData where
+  def = HumanTestData def def def
+
 data Op = Plus | Minus deriving (Show)
 
-empty            = State "" Pager.empty [] "" "" empty_human_test
-empty_human_test = HumanTestData 0 0 Plus
+instance Default Op where
+  def = Plus
 
+instance Default State where
+  def = State def def def def def def
 
-(^) = (<.>)
-infixl 9 ^
 
 ops = [Plus, Minus]
 nums = [0, 5, 10, 15, 20]
diff --git a/src/Panda/Type/StaticWidget.hs b/src/Panda/Type/StaticWidget.hs
new file mode 100644
--- /dev/null
+++ b/src/Panda/Type/StaticWidget.hs
@@ -0,0 +1,20 @@
+module Panda.Type.StaticWidget where
+
+import Panda.Helper.Env hiding (body)
+import Prelude hiding ((.), (/), (^), id, readFile)
+import Panda.Type.Reader
+
+data StaticWidget = StaticWidget
+  { name :: String
+  , body :: String
+  , reader :: Reader
+  }
+  deriving (Show, Eq)
+
+instance Markable StaticWidget where
+  markup x  = render_to_html (x.reader) (x.body)
+
+read_static_widget default_reader s = liftM2 (StaticWidget name) body (return reader) where
+  body = s.to_utf8.readFile
+  reader = s.take_extension.guess_reader.fromMaybe default_reader
+  name = s.takeFileName.dropExtension
diff --git a/src/Panda/Type/Theme.hs b/src/Panda/Type/Theme.hs
--- a/src/Panda/Type/Theme.hs
+++ b/src/Panda/Type/Theme.hs
@@ -14,31 +14,34 @@
   , css         :: [String]
   , js          :: [String]
   } deriving (Show, Read)
-  
+
+data ThemeData = 
+    Name
+  | Container
+  | Header
+  | Navigation
+  | Main
+  | Sidebar
+  | Footer
+  | Css
+  | Js
+  deriving (Eq, Show, Read)
+
 to_theme xs = Theme 
-  { name        = at "name"
-  , container   = at "container"
-  , header      = at "header"
-  , navigation  = at "navigation"
-  , main        = at "main"
-  , sidebar     = at "sidebar"
-  , footer      = at "footer"
-  , css         = at "css" .css_list
-  , js          = at "js"  .js_list
+  { name        = at Name
+  , container   = at Container
+  , header      = at Header
+  , navigation  = at Navigation
+  , main        = at Main
+  , sidebar     = at Sidebar
+  , footer      = at Footer
+  , css         = at Css .css_list
+  , js          = at Js  .js_list
   }
   where
-    at s = xs.lookup s .fromJust
-    css_list s = s.parse_list.map (\x -> "/theme/" ++ at "name" ++ "/css/" ++ x ++ ".css")
-    js_list s  = s.parse_list.map (\x -> "/theme/" ++ at "name" ++ "/js/" ++ x ++ ".js")
-    
-blank_theme = Theme
-  { name        = ""
-  , container   = ""
-  , header      = ""
-  , navigation  = ""
-  , main        = ""
-  , sidebar     = ""
-  , footer      = ""
-  , css         = [""]
-  , js          = [""]
-  }
+    at s = xs.lookup (s.show_data) .fromJust
+    css_list s = s.parse_list.map (\x -> "/theme/" ++ at Name ++ "/css/" ++ x ++ ".css")
+    js_list s  = s.parse_list.map (\x -> "/theme/" ++ at Name ++ "/js/" ++ x ++ ".js")
+
+instance Default Theme where
+  def = Theme def def def def def def def def def
diff --git a/src/Panda/View/Control/Post.hs b/src/Panda/View/Control/Post.hs
--- a/src/Panda/View/Control/Post.hs
+++ b/src/Panda/View/Control/Post.hs
@@ -22,7 +22,7 @@
 
 -- entry view
 view state xs x = (x.render_data +++ comment_view ).page state
-  where comment_view = for_extension Comment $ CommentV.list xs +++ CommentV.create state (x.uid.Comment.from_post_id)
+  where comment_view = only_for Comment $ CommentV.list xs +++ CommentV.create state (x.uid.Comment.from_post_id)
 
 -- list view
 list state = for_current_page p >>> map render >>> (+++ nav p G.root) >>> page state where 
diff --git a/src/Panda/View/Widget/Footer.hs b/src/Panda/View/Widget/Footer.hs
--- a/src/Panda/View/Widget/Footer.hs
+++ b/src/Panda/View/Widget/Footer.hs
@@ -5,7 +5,7 @@
 import qualified Panda.Config.Global as G
 
 
-footer c = div_class_id c "footer" <<
+static_footer c = toHtml
   [ toHtml $ copyright
   , toHtml $ "2008 "
   , toHtml $ G.blog_title
@@ -15,3 +15,8 @@
   , toHtml $ " using "
   , toHtml $ hotlink "http://www.haskell.org/" << "Haskell"
   ]
+  
+custom_footer _ | G.footer.isJust =  G.footer.fromJust.markup
+custom_footer x = static_footer x
+
+footer c = div_class_id c "footer" << custom_footer c
diff --git a/src/Panda/View/Widget/RSS.hs b/src/Panda/View/Widget/RSS.hs
--- a/src/Panda/View/Widget/RSS.hs
+++ b/src/Panda/View/Widget/RSS.hs
@@ -14,8 +14,8 @@
 -- RSS
 channel_rss_template = [ RSS.Language "en-us" ]
 
-render_rss x | G.summary_for_rss.is True = x.markup_summary.show
-render_rss x | otherwise                 = x.markup.show
+render_rss x  | G.summary_for_rss.is True = x.markup_summary.show
+              | otherwise                 = x.markup.show
 
 item_rss_template x = 
   [ Title $ x.Post.title
@@ -25,8 +25,11 @@
   , PubDate $ x.date
   ]
 
-item_uri x = nullURI { uriScheme = "http://", uriPath = host_link (x.uri) }
-rss_uri x  = nullURI { uriScheme = "http://", uriPath = host_link x }
+instance Default URI where
+  def = nullURI
+
+item_uri x = def { uriScheme = "http://", uriPath = host_link (x.uri) }
+rss_uri x  = def { uriScheme = "http://", uriPath = host_link x }
 
 rss categary s xs = RSS title  (rss_uri link) title channel_rss_template (xs.take 20 .map item_rss_template)
   .rssToXML.showXML
diff --git a/src/Panda/View/Widget/SearchBar.hs b/src/Panda/View/Widget/SearchBar.hs
--- a/src/Panda/View/Widget/SearchBar.hs
+++ b/src/Panda/View/Widget/SearchBar.hs
@@ -6,4 +6,4 @@
 import Panda.Type.Extension
 import Panda.Helper.StateHelper
 
-search_bar = for_extension Search $ div_id "search" << form ! [action (G.root / "search"), method "get"] << thediv << textfield "s"
+search_bar = only_for Search $ div_id "search" << form ! [action (G.root / "search"), method "get"] << thediv << textfield "s"
diff --git a/src/Panda/View/Widget/Sidebar.hs b/src/Panda/View/Widget/Sidebar.hs
--- a/src/Panda/View/Widget/Sidebar.hs
+++ b/src/Panda/View/Widget/Sidebar.hs
@@ -6,7 +6,7 @@
 
 import qualified Data.Set as Set
 import qualified Panda.Config.Global as G
-import qualified Panda.Type.Sidebar as Sidebar
+import qualified Panda.Type.StaticWidget as Sidebar
 import Panda.View.Widget.Helper
 
 -- model
diff --git a/src/Panda/View/Widget/Template.hs b/src/Panda/View/Widget/Template.hs
--- a/src/Panda/View/Widget/Template.hs
+++ b/src/Panda/View/Widget/Template.hs
@@ -27,7 +27,7 @@
     , div_id "page" << [ div_class (t.T.main) << body_content x, sidebar (t.T.sidebar) state ]
     , footer (t.T.footer)
     ]
-  , for_extension Analytics $ primHtml analytics_snippet
+  , only_for Analytics $ primHtml analytics_snippet
   ]
 
 template t state x = [html_head state, body t state x]
