diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,20 +1,13 @@
-Copyright (c) 2008 Wang, Jinjing
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+(c) 2008 Wang, Jinjing
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENMPS. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+This work ‘as-is’ we provide.
+No warranty, express or implied.
+We’ve done our best,
+to debug and test.
+Liability for damages denied.
 
+Permission is granted hereby,
+to copy, share, and modify.
+Use as is fit,
+free or for profit.
+On this notice these rights rely.
diff --git a/Panda/Config/Global.hs b/Panda/Config/Global.hs
--- a/Panda/Config/Global.hs
+++ b/Panda/Config/Global.hs
@@ -2,7 +2,6 @@
 
 import Panda.Helper.Env
 import Prelude hiding ((.), (/), id)
-import MPS
 
 db_id      = "db"
 flat_id    = "."
@@ -32,3 +31,5 @@
 author_email  = config_for "author_email"
 
 panda_url     = "http://github.com/nfjinjing/panda"
+
+per_page      = 7 :: Int
diff --git a/Panda/Controller/Application.hs b/Panda/Controller/Application.hs
--- a/Panda/Controller/Application.hs
+++ b/Panda/Controller/Application.hs
@@ -1,29 +1,27 @@
 {-# OPTIONS -fno-monomorphism-restriction #-}
 
-module Panda.Controller.Application (pages) where
-
+module Panda.Controller.Application where
 
 import qualified Data.Map as Map
 
 -- env
 import Panda.Helper.Env
 import Prelude hiding ((.), (/), id)
-import Kibro (kibro)          
-import Kibro.DB.Sqlite3      
 import Panda.Type.State hiding (pager)
 import qualified Panda.Config.Global as Config
 import qualified Panda.Type.Pager as Pager
 
 -- model
-import Panda.Model.Post as Post
-import Panda.Model.Tag as Tag
+import qualified Panda.Model.Post as Post
+import qualified Panda.Model.Tag as Tag
 
 -- view
 import qualified Panda.View.Theme.BluePrint.Post as PostV
-import qualified Panda.View.Theme.BluePrint.Template as T
+import qualified Panda.View.Theme.BluePrint.Template.Template as T
 import qualified Panda.View.Theme.BluePrint.Static as StaticV
 import qualified Panda.View.Theme.BluePrint.Tag as TagV
-import qualified Panda.View.RSS as RSS
+import qualified Panda.View.Theme.BluePrint.Search as SearchV
+import qualified Panda.View.RSS as RSSV
 
 
 
@@ -32,26 +30,30 @@
 pages = 
   [ ("^/$"                  ,index             )
   , ("^/([?].+$)?$"         ,index             )
-  , ("^/rss.xml$"           ,blog_feed         )
+  , ("^/rss.xml$"           ,index_feed        )
   , (blog_regex             ,blog              )
   , ("^/static/."           ,static            )
+  , ("^/tag/.*/rss.xml$"    ,tag_feed          )
   , ("^/tag/."              ,tag               )
-  , ("^/tag/.*([?].+$)?$"   ,index             )
+  , ("^/search"             ,search            )
   ]
 
+per_page = Config.per_page
+
 index = do
   blogs <- Post.list.liftIO
-  p <- pager 10 $ blogs.length
+  p <- pager per_page $ blogs.length
   tags <- Tag.list.liftIO
   let nav = if p.Pager.current == 1 then Home else Other
   let state = State Config.blog_id p tags nav
   
   blogs.map (Tag.fill_tag tags) .PostV.list state .output_html
 
-blog_feed = do
+index_feed = do
   blogs <- Post.list.liftIO
-  blogs.RSS.rss.output
+  blogs.RSSV.rss.output
 
+
 blog = do
   id <- uri <.> ("blog/" ++)
   blog <- Post.get id .liftIO
@@ -71,11 +73,32 @@
 tag = do
   id <- uri
   tags <- Tag.list.liftIO
-  let tag_name = Tag.name_from_id id
+  let tag_name = Tag.id_to_name id
   case Tag.tag_map' tags .Map.lookup tag_name of
     Nothing -> "page not found" .output
     Just blog_set -> do
       blogs <- blog_set.to_list.rsort.mapM (Post.get) .liftIO <.> map (Tag.fill_tag tags)
-      p <- pager 10 $ blogs.length
+      p <- pager per_page $ blogs.length
       let state = State id p tags Other
       blogs.TagV.view state.output_html
+
+tag_feed = do
+  id <- uri <.> (split "/" >>> init >>> join "/")
+  tags <- Tag.list.liftIO
+  let tag_name = Tag.id_to_name id
+  case Tag.tag_map' tags .Map.lookup tag_name of
+    Nothing -> "page not found" .output
+    Just blog_set -> do
+      blogs <- blog_set.to_list.rsort.mapM (Post.get) .liftIO <.> map (Tag.fill_tag tags)
+      blogs.RSSV.rss.output
+
+search = do
+  s <- param_with_default "s" ""
+  blogs <- Post.search s .liftIO
+
+  p <- pager per_page $ blogs.length
+  tags <- Tag.list.liftIO
+  query <- uri
+  let state = State query p tags Other
+
+  blogs.map (Tag.fill_tag tags) .SearchV.view state s.output_html
diff --git a/Panda/Helper/Env.hs b/Panda/Helper/Env.hs
--- a/Panda/Helper/Env.hs
+++ b/Panda/Helper/Env.hs
@@ -1,6 +1,5 @@
 module Panda.Helper.Env  (
     module MPS                 
-  , module System.Directory    
   , module Control.Monad       
   , module Control.Arrow       
   , module Data.List           
@@ -14,16 +13,12 @@
 ) where
   
 import MPS
-import System.Directory
-import Kibro hiding (tag)
-import Kibro.DB.Sqlite3
 import Control.Monad hiding (join)
 import Control.Arrow ((>>>))
 import Data.List
 import Network.URI
 import Network.CGI
 import Text.Pandoc.UTF8
-import Text.XHtml.Strict
 import System.Locale
 import System.Time.Parse
 import Panda.Helper.Helper
diff --git a/Panda/Helper/Escape.hs b/Panda/Helper/Escape.hs
new file mode 100644
--- /dev/null
+++ b/Panda/Helper/Escape.hs
@@ -0,0 +1,22 @@
+module Panda.Helper.Escape where
+
+
+import Text.XML.HaXml hiding ((!))
+import Text.XML.HaXml.Parse (xmlParseWith, document)
+import Text.XML.HaXml.Lex (xmlLex)
+
+
+
+unescape :: String -> String
+unescape = concatMap ctext . xmlUnEscapeContent stdXmlEscaper .
+              unwrapTag .
+              either error id . fst . xmlParseWith document .
+              xmlLex "oops, lexer failed" . wrapWithTag "t"
+  where
+    ctext (CString _ txt _)         = txt
+    ctext (CRef (RefEntity name) _) = '&' : name ++ ";" -- skipped by escaper
+    ctext (CRef (RefChar num) _)    = '&' : '#' : show num ++ ";" -- ditto
+    ctext _                 = error "oops, can't unescape non-cdata"
+    wrapWithTag t s = concat ["<", t, ">", s, "</", t, ">"]
+    unwrapTag (Document _ _ (Elem _ _ c) _) = c
+    unwrapTag _                             = error "oops, not wrapped"
diff --git a/Panda/Helper/Helper.hs b/Panda/Helper/Helper.hs
--- a/Panda/Helper/Helper.hs
+++ b/Panda/Helper/Helper.hs
@@ -8,35 +8,43 @@
 import Control.Arrow ((>>>), (&&&))
 import Text.XHtml.Strict
 import Control.Monad hiding (join)
+import Data.Maybe
 
-import Panda.Type.Pager as Pager
+import Panda.Type.Pager as Pager hiding (empty)
 import MPS
 import Prelude hiding ((.), (/), id)
+import Panda.Helper.Escape
+import Char
+import Data.List
+import System.Directory
 
 (/) = (</>)
 
 
+
 -- controller
-uri = do
-  uri <- requestURI
-  uri.uriPath.urlDecode.tail.return
+uri = requestURI <.> (uriPath >>> urlDecode >>> tail)
   
-markdown_link l s = ["[", s, "]", "(", l, ")"] .join'
-
 params = do
   query_string <- requestURI <.> uriQuery
   case query_string of
-    '?':s -> s.split "&" .map (split "=" >>> tuple2) .return
+    '?':s -> s.formDecode .return
     otherwise -> return []
 
 param_with_default s d = do
   ps <- params
   return $ case ps.lookup s of
     Nothing -> d
-    Just x -> x.read
+    Just x -> x.unescape.strip
 
+input_with_default s d = do
+  input <- getInput s
+  return $ case input of
+    Nothing -> d
+    Just x -> x.unescape.strip
+
 pager length total = liftM5 ( Pager length ) current has_next has_previous next previous where
-  current      = param_with_default "page" 1
+  current      = param_with_default "page" "1" <.> read
   has_next     = current <.> ( (* length) >>> (< total.fromIntegral) )
   has_previous = current <.> (> 1)
   next         = current <.> (+ 1)
@@ -46,27 +54,21 @@
 for_current_page p xs = xs.drop ((p.Pager.current - 1) * p.Pager.length) .take (p.Pager.length)
 
 
-
-
 -- view
-id           = identifier
+id               = identifier
 
-css_link l   = itag "link" ! [rel "stylesheet", thetype "text/css", href l]
-js_link l    = itag "script" ! [thetype "text/javascript", src l]
-svg s a w h  = image ! [src ("/svg/" ++ s), height (h.show), width (w.show), alt a]
+css_link l       = itag "link" ! [rel "stylesheet", thetype "text/css", href l]
+js_link l        = itag "script" ! [thetype "text/javascript", src l]
+rss_link l       = itag "link" ! [rel "alternate", thetype "application/rss+xml", href l, title "RSS 2.0"]
+meta_tag         = meta ! [httpequiv "Content-Type", content "text/html; charset=utf-8"]
 
-meta_tag     = meta ! [httpequiv "Content-Type", content "text/html; charset=utf-8"]
 
-div_id s     = thediv ! [id s]
-div_class s  = thediv ! [theclass s]
+div_id s         = thediv ! [id s]
+div_class s      = thediv ! [theclass s]
 div_class_id x y = thediv ! [theclass x, id y]
-space        = hr ! [theclass "space"]
 
-sep_by _ []  = toHtml ""
-sep_by _ [x] = toHtmlFromList [x]
-sep_by x xs  = ( init >>> map (+++ x) ) &&& last >>> splash (+++) $ xs
+output_html      = output ... renderHtml
 
-output_html  = output ... renderHtml
 
 ie s = 
   [ "<!-- [if IE]>"
@@ -81,3 +83,13 @@
   uriQuery = "",
   uriFragment = ""
   }
+
+
+
+-- generic
+lower = map toLower
+upper = map toUpper
+
+ls s = getDirectoryContents s <.> (\\ [".", ".."])
+
+filter_comment = lines >>> map strip >>> reject null >>> reject (head >>> (== '#')) >>> join "\n"
diff --git a/Panda/Model/Post.hs b/Panda/Model/Post.hs
--- a/Panda/Model/Post.hs
+++ b/Panda/Model/Post.hs
@@ -3,7 +3,7 @@
 module Panda.Model.Post where
 
 -- env
-import Panda.Helper.Env
+import Panda.Helper.Env hiding (match)
 import Prelude hiding ((.), (/), id)
 import qualified Panda.Config.Global as Config
 
@@ -15,9 +15,7 @@
   }
   deriving (Show, Eq)
 
-list = do
-  ids <- getDirectoryContents Config.blog_uri <.> (\\ [".", ".."]) <.> rsort <.> map ("" / Config.blog_id /)
-  mapM get ids
+list = ls Config.blog_uri <.> rsort <.> map (Config.blog_id /) >>= mapM get
 
 get id       = liftM2 (Post id (get_title id) ) (get_body id) (return [])
 get_title id = id.fromUTF8.words.tail.join " "
@@ -28,3 +26,6 @@
   Nothing -> parse_date "2000-1-1".fromJust
   Just x -> x
 
+match s x = [title, body] .map (send_to x >>> lower >>> isInfixOf (s.lower)) .or
+search "" = return []
+search s  = list <.> filter (match s)
diff --git a/Panda/Model/Tag.hs b/Panda/Model/Tag.hs
--- a/Panda/Model/Tag.hs
+++ b/Panda/Model/Tag.hs
@@ -19,40 +19,21 @@
   }
   deriving (Show, Eq)
 
-name x = x.uid.name_from_id
-name_from_id x = x.split "/" .tail.join'
-sorted xs = xs.List.sortBy(\a b -> (b.resources.Set.size) `compare` (a.resources.Set.size))
-id_from_name x = tag_id / x
-
-list = do
-  ids <- getDirectoryContents Config.tag_uri <.> (\\ [".", ".."]) <.> map ("" / Config.tag_id /)
-  mapM get ids
-
-get id       = get_resources id <.> Tag id
-get_resources id  = (Config.flat_uri / id) .readFile 
-  <.> lines <.> map strip <.> reject empty <.> reject (head >>> (== '#')) <.> map (blog_id / ) <.> to_set
+name x       = x.uid.id_to_name
+id_to_name x = x.split "/" .tail.join'
+sorted xs    = xs.List.sortBy(\a b -> (b.resources.Set.size) `compare` (a.resources.Set.size))
+name_to_id x = tag_id / x
 
+list = ls Config.tag_uri <.> map (Config.tag_id /) >>= mapM get
 
+get id = get_resources id <.> Tag id
+get_resources id = (Config.flat_uri / id) .readFile 
+  <.> filter_comment <.> lines <.> map (blog_id / ) <.> to_set
 
 
--- many to many relationship is modeled using 2 maps
--- one from tags, and the other from resources
-
-to_tuple x = (x.name, x.resources)
-
-tag_map' xs = xs . map (to_tuple) . to_h
-tag_map = list <.> tag_map'
-
-tag_reverse_map' xs = res.labeling (for_resource xs) where
-  res = xs.map resources .reduce Set.union .to_list
-
-tag_reverse_map = list <.> tag_reverse_map'
-
-uncategorized = []
-for_resource xs x = case tags of 
-    [] -> uncategorized
-    otherwise -> tags
-  where
-    tags = xs.select (resources >>> Set.member x) .map name
+to_tuple x        = (x.name, x.resources)
+tag_map' xs       = xs . map (to_tuple) . to_h
+tag_map           = list <.> tag_map'
 
-fill_tag xs x = x { Post.tags = for_resource xs (x.Post.uid) }
+for_resource xs x = xs.select (resources >>> Set.member x) .map name
+fill_tag xs x     = x { Post.tags = for_resource xs (x.Post.uid) }
diff --git a/Panda/Type/State.hs b/Panda/Type/State.hs
--- a/Panda/Type/State.hs
+++ b/Panda/Type/State.hs
@@ -13,5 +13,4 @@
   , nav_location :: NavLocation
   }
   
-data NavLocation = Home | About | Other
-  deriving (Eq, Show)
+data NavLocation = Home | About | Other deriving (Eq, Show)
diff --git a/Panda/View/RSS.hs b/Panda/View/RSS.hs
--- a/Panda/View/RSS.hs
+++ b/Panda/View/RSS.hs
@@ -14,9 +14,7 @@
 entry_uri x = "/" ++ Post.uid x.urlEncode.split "/".tail.join "/"
 
 -- RSS
-channel_rss_template = 
-  [ Language "en-us"
-  ]
+channel_rss_template = [ Language "en-us" ]
 
 item_rss_template x = 
   [ Title $ x.Post.title
diff --git a/Panda/View/Theme/BluePrint/Body.hs b/Panda/View/Theme/BluePrint/Body.hs
deleted file mode 100644
--- a/Panda/View/Theme/BluePrint/Body.hs
+++ /dev/null
@@ -1,60 +0,0 @@
-module Panda.View.Theme.BluePrint.Body where
-
--- env
-import Panda.Helper.Env
-import Prelude hiding ((.), (/), id, span)
-import Panda.Config.Global as Config
-import qualified Panda.Type.State as State
-import Text.XHtml.Strict
-
--- view
-import Panda.View.Theme.BluePrint.Sidebar
-import Panda.View.Theme.BluePrint.Footer
-
-
-html_body state x = body << container << 
-  [ body_header state
-  , div_id "page" << [ body_content x, html_sidebar state ]
-  , html_footer
-  ]
-
-container   = div_class "container"
-
-body_header state = toHtml
-  [ div_class_id "column span-12 first" "header" << 
-    [ search_form
-    , site_name
-    ]
-  , div_class_id "column span-12 first large" "nav" << navigation state
-  ]
-
-search_form = spaceHtml
-search_form' = 
-  div_id "search" << gui "/search" << thediv << 
-    textfield "s" ! [strAttr "onFocus" "clearInput('s', 'Search')", strAttr "onBlur" "clearInput('s', 'Search')"]
-  
-site_name = toHtml $
-  [ toHtml $ hotlink "/" ! [theclass "logo"] << ""
-  , h1 << Config.blog_title
-  , div_class "description" << Config.blog_subtitle
-  ]
-
-navigation state = div_class "content" <<
-  ulist << 
-  [ li ! [theclass ("first" ++ current_home)] << home_link
-  , li ! [theclass ("page_item page-item-2" ++ current_about)] << about
-  ]
-  where
-    nav = state.State.nav_location
-    current = " current_page_item"
-    current_home = at State.Home
-    current_about = at State.About
-    at x = if nav == x then current else ""
-
-home_link   = hotlink "/" << "Home"
-about       = hotlink "/static/about" << "About"
-
-
-body_content x = div_class_id "column span-9 first" "maincontent" <<
-  div_class "content" << x
-
diff --git a/Panda/View/Theme/BluePrint/Footer.hs b/Panda/View/Theme/BluePrint/Footer.hs
deleted file mode 100644
--- a/Panda/View/Theme/BluePrint/Footer.hs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Panda.View.Theme.BluePrint.Footer where
-  
-import Panda.Helper.Env
-import Prelude hiding ((.), (/), id, span)
-import Panda.Config.Global as Config
-import qualified Panda.Type.State as State
-import Text.XHtml.Strict
-
-
-import Panda.Config.Global as Config
-
-html_footer = div_id "footer" <<
-  [ toHtml $ copyright
-  , toHtml $ "2008 "
-  , toHtml $ Config.blog_title
-  , toHtml $ br
-  , toHtml $ "Powered by "
-  , toHtml $ hotlink Config.panda_url << "Panda"
-  , toHtml $ " using "
-  , toHtml $ hotlink "http://www.haskell.org/" << "Haskell"
-  ]
diff --git a/Panda/View/Theme/BluePrint/Header.hs b/Panda/View/Theme/BluePrint/Header.hs
deleted file mode 100644
--- a/Panda/View/Theme/BluePrint/Header.hs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Panda.View.Theme.BluePrint.Header where
-
-import Panda.Helper.Env
-import Prelude hiding ((.), (/), id, span)
-import Panda.Config.Global as Config
-import qualified Panda.Type.State as State
-import Text.XHtml.Strict
-
-
-html_head  = header << [meta_tag, title_tag, screen_css, wp_css] -- , ie_css, custom_css]
-
-title_tag  = thetitle << Config.blog_title
-screen_css = css_link "/theme/blueprint/wp/css/screen.css"
-wp_css     = css_link "/theme/blueprint/wp/css/blueprint-wp.css"
--- ie_css  = ie $ css_link "theme/blueprint/core/ie.css"
-custom_css = css_link "/theme/blueprint/wp/css/custom.css"
diff --git a/Panda/View/Theme/BluePrint/Helper.hs b/Panda/View/Theme/BluePrint/Helper.hs
--- a/Panda/View/Theme/BluePrint/Helper.hs
+++ b/Panda/View/Theme/BluePrint/Helper.hs
@@ -1,34 +1,32 @@
 module Panda.View.Theme.BluePrint.Helper where
 
-import Kibro
 
-import MPS
-import Prelude hiding ((.), (/), id)
-import Control.Arrow ((>>>))
 
-import Panda.Helper.Helper
-import Panda.View.Theme.BluePrint.Template
-import Panda.Model.Post as Post
+import Panda.Helper.Env
+import Prelude hiding ((.), (/), id, span)
 import Panda.Config.Global as Config
-import Panda.Type.Pager as Pager
-import Network.URI
-import Text.RSS
-import System.Time
-import System.Locale
 import qualified Panda.Type.State as State
+import Text.XHtml.Strict
+  
+import Panda.View.Theme.BluePrint.Template.Template
+import Panda.Model.Post as Post
+import Panda.Type.Pager as Pager
 
+
 nav p r = 
   [ div_class "alighleft" << nav_next p r
   , div_class "alignright" << nav_previous p r
   ]
   
 nav_previous p r = if p.Pager.has_previous 
-  then toHtml $ hotlink ( r ++ "?page=" ++ p.Pager.previous.show ) << previous_sign
+  then toHtml $ hotlink ( r' ++ "page=" ++ p.Pager.previous.show ) << previous_sign
   else spaceHtml
-
+  where r' = if isSuffixOf "&" r then r else r ++ "?"
+    
 nav_next p r = if p.Pager.has_next
-  then toHtml $ hotlink ( r ++ "?page=" ++ p.Pager.next.show ) << next_sign
+  then toHtml $ hotlink ( r' ++ "page=" ++ p.Pager.next.show ) << next_sign
   else spaceHtml
+  where r' = if isSuffixOf "&" r then r else r ++ "?"
 
 next_sign     = "Next Entries »"
 previous_sign = "« Previous Entries"
diff --git a/Panda/View/Theme/BluePrint/Post.hs b/Panda/View/Theme/BluePrint/Post.hs
--- a/Panda/View/Theme/BluePrint/Post.hs
+++ b/Panda/View/Theme/BluePrint/Post.hs
@@ -17,13 +17,13 @@
 
 -- view
 import Panda.View.Theme.BluePrint.Helper
-import Panda.View.Theme.BluePrint.Template
+import Panda.View.Theme.BluePrint.Template.Template
 
 -- HTML
 -- render single entry
 entry x = div_class "post" << [entry_title, entry_mark, entry_body] where
   entry_title = x.title_link
-  entry_body  = p ! [theclass "entry"] << x.Post.body.markup
+  entry_body  = div_class "entry" << x.Post.body.markup
   entry_mark  = p ! [theclass "small"] << 
     [ x.blog_date, x.blog_tags ]
 
@@ -34,7 +34,8 @@
 blog_tags x | x.tags.null = toHtml ""
 blog_tags x | otherwise   = toHtml " | " +++ toHtml ["Published in ".toHtml, x.tags.map tag_link .intersperse (", ".toHtml) .toHtml]
 
-tag_link s = toHtml $ hotlink ("/tag/" ++ s ) << s
+tag_link s                = toHtml $ hotlink ("/tag/" ++ s ) << s
+
 
 -- entry view
 view state x = x.entry.page state
diff --git a/Panda/View/Theme/BluePrint/Search.hs b/Panda/View/Theme/BluePrint/Search.hs
new file mode 100644
--- /dev/null
+++ b/Panda/View/Theme/BluePrint/Search.hs
@@ -0,0 +1,16 @@
+module Panda.View.Theme.BluePrint.Search where
+  
+import Panda.Helper.Env
+import Prelude hiding ((.), (/), id, span)
+import Panda.Config.Global as Config
+import qualified Panda.Type.State as State
+import Text.XHtml.Strict
+
+-- view
+import Panda.View.Theme.BluePrint.Post hiding (view)
+import Panda.View.Theme.BluePrint.Helper
+import Panda.View.Theme.BluePrint.Template.Template
+
+view state s = for_current_page p >>> map entry >>> (+++ nav p ("/search" ++ "?s=" ++ (s.urlEncode) ++ "&")) >>> page state
+  where p = state.State.pager
+
diff --git a/Panda/View/Theme/BluePrint/Sidebar.hs b/Panda/View/Theme/BluePrint/Sidebar.hs
deleted file mode 100644
--- a/Panda/View/Theme/BluePrint/Sidebar.hs
+++ /dev/null
@@ -1,34 +0,0 @@
-module Panda.View.Theme.BluePrint.Sidebar where
-
-import Panda.Helper.Env
-import Prelude hiding ((.), (/), id, span)
-import Panda.Config.Global as Config
-import qualified Panda.Type.State as State
-import Text.XHtml.Strict
-
-import qualified Data.Set as Set
-
--- model
-import Panda.Model.Tag as Tag
-
-html_sidebar state = 
-  div_class_id "column span-3 last" "sidebar" << unordList
-    [ feed
-    , [hr]
-    , tag_list $ state.State.tags
-    ]
-
-feed = 
-  [ h2 << "Keep Update"
-  , p ! [theclass "small"] << rss_link
-  ]
-
-rss_link = hotlink "/rss.xml" << 
-  [ -- image ! [src "/image/feed.png", alt "feed link", height "15", width "15"]
-    "Subscribe to Feed" ]
-    
-tag_list tags = 
-  [ h2 << "Tags"
-  , unordList $ tags.Tag.sorted.map tag_link]
-  
-tag_link x = hotlink ("/" ++ x.uid) << x.Tag.name +++ (" (" ++ x.Tag.resources.Set.size.show ++ ")")
diff --git a/Panda/View/Theme/BluePrint/Static.hs b/Panda/View/Theme/BluePrint/Static.hs
--- a/Panda/View/Theme/BluePrint/Static.hs
+++ b/Panda/View/Theme/BluePrint/Static.hs
@@ -6,6 +6,6 @@
 import qualified Panda.Type.State as State
 import Text.XHtml.Strict
 
-import Panda.View.Theme.BluePrint.Template
+import Panda.View.Theme.BluePrint.Template.Template
 
 view tags x = x.markup.page tags
diff --git a/Panda/View/Theme/BluePrint/Tag.hs b/Panda/View/Theme/BluePrint/Tag.hs
--- a/Panda/View/Theme/BluePrint/Tag.hs
+++ b/Panda/View/Theme/BluePrint/Tag.hs
@@ -12,7 +12,7 @@
 -- view
 import Panda.View.Theme.BluePrint.Post hiding (view)
 import Panda.View.Theme.BluePrint.Helper
-import Panda.View.Theme.BluePrint.Template
+import Panda.View.Theme.BluePrint.Template.Template
 
 view state = for_current_page p >>> map entry >>> (+++ nav p ("/" ++ tag_id)) >>> page state
   where p = state.State.pager
diff --git a/Panda/View/Theme/BluePrint/Template.hs b/Panda/View/Theme/BluePrint/Template.hs
deleted file mode 100644
--- a/Panda/View/Theme/BluePrint/Template.hs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Panda.View.Theme.BluePrint.Template where
-
-import Panda.View.Theme.BluePrint.Header
-import Panda.View.Theme.BluePrint.Body
-
-import Panda.Helper.Env
-
-page state x = 
-  [ html_head
-  , html_body state x
-  ]
diff --git a/Panda/View/Theme/BluePrint/Template/Body.hs b/Panda/View/Theme/BluePrint/Template/Body.hs
new file mode 100644
--- /dev/null
+++ b/Panda/View/Theme/BluePrint/Template/Body.hs
@@ -0,0 +1,61 @@
+module Panda.View.Theme.BluePrint.Template.Body where
+
+-- env
+import Panda.Helper.Env
+import Prelude hiding ((.), (/), id, span)
+import Panda.Config.Global as Config
+import qualified Panda.Type.State as State
+import Text.XHtml.Strict
+
+-- view
+import Panda.View.Theme.BluePrint.Template.Sidebar
+import Panda.View.Theme.BluePrint.Template.Footer
+
+
+html_body state x = body << container << 
+  [ body_header state
+  , div_id "page" << [ body_content x, html_sidebar state ]
+  , html_footer
+  ]
+
+container   = div_class "container"
+
+body_header state = toHtml
+  [ div_class_id "column span-12 first" "header" << 
+    [ search_form
+    , site_name
+    ]
+  , div_class_id "column span-12 first large" "nav" << navigation state
+  ]
+
+-- search_form = spaceHtml
+search_form = 
+  div_id "search" << form ! [action "/search", method "get"] << thediv << 
+    textfield "s" -- ! [strAttr "onFocus" "clearInput('s', 'Search')", strAttr "onBlur" "clearInput('s', 'Search')"]
+  
+site_name = toHtml $
+  [ toHtml $ hotlink "/" ! [theclass "logo"] << ""
+  , h1 << Config.blog_title
+  , div_class "description" << Config.blog_subtitle
+  ]
+
+navigation state = div_class "content" <<
+  ulist << 
+  [ li ! [theclass ("first" ++ current_home)] << home_link
+  , li ! [theclass ("page_item page-item-2" ++ current_about)] << about
+  ]
+  where
+    nav           = state.State.nav_location
+    current       = " current_page_item"
+    current_home  = at State.Home
+    current_about = at State.About
+    at x          = if nav == x then current else ""
+
+
+home_link   = hotlink "/" << "Home"
+about       = hotlink "/static/about" << "About"
+
+
+body_content x = div_class_id "column span-9 first" "maincontent" <<
+  div_class "content" << x
+
diff --git a/Panda/View/Theme/BluePrint/Template/Footer.hs b/Panda/View/Theme/BluePrint/Template/Footer.hs
new file mode 100644
--- /dev/null
+++ b/Panda/View/Theme/BluePrint/Template/Footer.hs
@@ -0,0 +1,21 @@
+module Panda.View.Theme.BluePrint.Template.Footer where
+  
+import Panda.Helper.Env
+import Prelude hiding ((.), (/), id, span)
+import Panda.Config.Global as Config
+import qualified Panda.Type.State as State
+import Text.XHtml.Strict
+
+
+import Panda.Config.Global as Config
+
+html_footer = div_id "footer" <<
+  [ toHtml $ copyright
+  , toHtml $ "2008 "
+  , toHtml $ Config.blog_title
+  , toHtml $ br
+  , toHtml $ "Powered by "
+  , toHtml $ hotlink Config.panda_url << "Panda"
+  , toHtml $ " using "
+  , toHtml $ hotlink "http://www.haskell.org/" << "Haskell"
+  ]
diff --git a/Panda/View/Theme/BluePrint/Template/Header.hs b/Panda/View/Theme/BluePrint/Template/Header.hs
new file mode 100644
--- /dev/null
+++ b/Panda/View/Theme/BluePrint/Template/Header.hs
@@ -0,0 +1,18 @@
+module Panda.View.Theme.BluePrint.Template.Header where
+
+import Panda.Helper.Env
+import Prelude hiding ((.), (/), id, span)
+import Panda.Config.Global as Config
+import qualified Panda.Type.State as State
+import Text.XHtml.Strict
+
+
+html_head  = header << [meta_tag, title_tag, screen_css, wp_css, custom_css, rss_tag] -- , ie_css, custom_css]
+
+title_tag  = thetitle << Config.blog_title
+screen_css = css_link "/theme/blueprint/wp/css/screen.css"
+wp_css     = css_link "/theme/blueprint/wp/css/blueprint-wp.css"
+-- ie_css  = ie $ css_link "theme/blueprint/core/ie.css"
+custom_css = css_link "/theme/blueprint/wp/css/custom.css"
+
+rss_tag = rss_link "rss.xml"
diff --git a/Panda/View/Theme/BluePrint/Template/Sidebar.hs b/Panda/View/Theme/BluePrint/Template/Sidebar.hs
new file mode 100644
--- /dev/null
+++ b/Panda/View/Theme/BluePrint/Template/Sidebar.hs
@@ -0,0 +1,41 @@
+module Panda.View.Theme.BluePrint.Template.Sidebar where
+
+import Panda.Helper.Env hiding (rss_link)
+import Prelude hiding ((.), (/), id, span)
+import Panda.Config.Global as Config
+import qualified Panda.Type.State as State
+import Text.XHtml.Strict
+
+import qualified Data.Set as Set
+
+-- model
+import Panda.Model.Tag as Tag
+
+html_sidebar state = 
+  div_class_id "column span-3 last" "sidebar" << unordList
+    [ feed state
+    , hr
+    , tag_list $ state.State.tags
+    ]
+
+feed state = toHtml
+  [ h2 << "Subscribe"
+  , p ! [theclass "feed"] << rss_link state
+  ]
+
+rss_link state = 
+  if tagged 
+  then
+    let tag_name = uid.split "/".tail.first in
+      link ("tag" / tag_name) tag_name
+  else link "" "Home"
+  where
+    uid = State.uid state
+    tagged = uid.match "^tag/.+" .isJust
+    link r s = hotlink ("/" / r / "rss.xml") ! [ theclass "feedlink" ] << s
+
+tag_list tags = toHtml
+  [ h2 << "Tags"
+  , unordList $ tags.Tag.sorted.map tag_link]
+  
+tag_link x = hotlink ("/" ++ x.uid) << x.Tag.name +++ (" (" ++ x.Tag.resources.Set.size.show ++ ")")
diff --git a/Panda/View/Theme/BluePrint/Template/Template.hs b/Panda/View/Theme/BluePrint/Template/Template.hs
new file mode 100644
--- /dev/null
+++ b/Panda/View/Theme/BluePrint/Template/Template.hs
@@ -0,0 +1,11 @@
+module Panda.View.Theme.BluePrint.Template.Template where
+
+import Panda.View.Theme.BluePrint.Template.Header
+import Panda.View.Theme.BluePrint.Template.Body
+
+import Panda.Helper.Env
+
+page state x = 
+  [ html_head
+  , html_body state x
+  ]
diff --git a/changelog.markdown b/changelog.markdown
new file mode 100644
--- /dev/null
+++ b/changelog.markdown
@@ -0,0 +1,25 @@
+0.0.0.3
+--------
+
+### New Features
+
+* Search
+* Feed per tag
+* Theme through CSS
+
+### Migration
+
+* Checkout `public/theme/blueprint/wp/css/custom.css` in `panda-template`
+
+0.0.0.2
+--------
+
+### General
+
+* A new blueprint theme adopted from <http://www.fireandknowledge.org/archives/2007/09/05/blueprint-wordpress-theme/>
+* Support for tags, see `panda-template` for example.
+* Support for subtitle
+
+### Migration
+
+* Add a tag folder under `db`
diff --git a/panda.cabal b/panda.cabal
--- a/panda.cabal
+++ b/panda.cabal
@@ -1,5 +1,5 @@
 Name:                 panda
-Version:              0.0.0.2
+Version:              0.0.0.3
 Build-type:           Simple
 Synopsis:             Simple Static Blog Engine
 Description:          Simple Static Blog Engine
@@ -11,26 +11,34 @@
 Cabal-version:        >= 1.2
 category:             Web
 homepage:             http://github.com/nfjinjing/panda/
+data-files:			      readme.markdown, changelog.markdown
 
 library
-  build-depends: base, cgi, network, pandoc >= 0.46, old-locale, old-time, directory, filepath, containers >= 0.1.0.2, mps >= 0.0, parsedate >= 3000.0.0, rss >= 3000.1.0, xhtml >= 3000.2.0.0, kibro >= 0.0
+  build-depends: base, cgi, network, haskell98, pandoc >= 0.46, old-locale, old-time, directory, filepath, containers >= 0.1.0.2, mps >= 0.0, parsedate >= 3000.0.0, rss >= 3000.1.0, xhtml >= 3000.2.0.0, kibro >= 0.0, HaXml >= 1.19.4
   exposed-modules:  Panda
                     Panda.Controller.Application
                     Panda.Config.Global
+                    
                     Panda.Helper.Helper
+                    Panda.Helper.Escape
                     Panda.Helper.Env
+
                     Panda.Model.Post
                     Panda.Model.Tag
+
                     Panda.Type.Pager
                     Panda.Type.State
+
                     Panda.View.RSS
                     Panda.View.Theme.BluePrint.Post
                     Panda.View.Theme.BluePrint.Static
-                    Panda.View.Theme.BluePrint.Template
-                    Panda.View.Theme.BluePrint.Header
-                    Panda.View.Theme.BluePrint.Body
-                    Panda.View.Theme.BluePrint.Footer
-                    Panda.View.Theme.BluePrint.Sidebar
                     Panda.View.Theme.BluePrint.Helper
                     Panda.View.Theme.BluePrint.Tag
+                    Panda.View.Theme.BluePrint.Search
+                    Panda.View.Theme.BluePrint.Template.Template
+                    Panda.View.Theme.BluePrint.Template.Header
+                    Panda.View.Theme.BluePrint.Template.Body
+                    Panda.View.Theme.BluePrint.Template.Footer
+                    Panda.View.Theme.BluePrint.Template.Sidebar
+ 
                     
diff --git a/readme.markdown b/readme.markdown
new file mode 100644
--- /dev/null
+++ b/readme.markdown
@@ -0,0 +1,123 @@
+Panda static blogging engine
+==============================
+
+Sample file db structure
+-------------------------
+
+    db
+    |---- blog
+    |     |---- 08-09-01 first post
+    |     |---- 09-09-02 learn javascript
+    |
+    |---- tag
+          |---- programming
+          |---- funny
+
+Why
+----
+
+* Blog entries are stored locally in markdown format ( can be changed easily with more hacking )
+* Remote server is a mirror of local repository
+* No server side API for publishing / editing, just use Darcs, Git or any SCM
+* No need to find external hosting of your videos, images or sound. Put them in public folder ( still managed by SCM if you wish )
+* Embed any HTML snippets
+* Statically typed HTML combinator = valid html
+* Based on Kibro
+* Freshman level MVC design
+
+Quick Demo
+-----------
+
+It powers [my blog](http://jinjing.blog.easymic.com) ;)
+
+Note: the demo might run on an experimental branch, so differences from the cabal version could occur.
+        
+Status
+-------
+
+Panda is in its early stage. I got tired of importing / exporting blogs when switching blogging platforms, 
+I needed a way to not be bounded to any service API, and that's the main design goal for Panda. There's no theming yet
+(except that you wish to hack the source).
+
+The main benefit is that if I ever wanted to stop using Panda, all my blogs and resources are in manageable states.
+
+Install
+--------
+
+### install [lighttpd](http://www.lighttpd.net/ )
+
+
+### install panda
+
+    cabal install panda
+
+### bootstrap
+
+    # panda is a kibro project
+    kibro new myblog
+    cd myblog
+    
+    # get a template to start
+    rm -r db; rm -r public
+    git clone git://github.com/nfjinjing/panda-template.git db
+    sh db/scripts/bootstrap.sh
+    
+### run
+
+	kibro start
+
+It should be running on `http://127.0.0.1:3000` now.
+
+Since Panda is based on Kibro, it helps to read how [Kibro](http://chrisdone.com/blog/2008/08/06/kibro-haskell-lighttpd-and-fastcgi/) works.
+
+Goodies
+--------
+
+Install `Ruby` / `Rake`, then `rake -T` to see a list of helper commands.
+
+Config
+-------
+
+Edit `db/config/site.txt`
+
+    blog_title   = My shiny blog
+    host_name    = yourhost.com
+    author_email = your_mail@yourhost.com
+
+Restart required. (hint: `rake r`)
+
+
+Future
+------
+
+The template db is just a starting point for you to experiment on. However, I would encourage you to keep your own db in your own SCM, that way, you will never lose your data and never have to care about application logic again.
+
+There are many things could be done. Whatever there will be, the key idea is simplest data / folder structure, absolutely no parsing, no xml, no code is data like and stuff :)
+
+Hacking
+--------
+
+Another way to get Panda running with source is:
+
+    # clone the source
+    git clone git://github.com/nfjinjing/panda.git myblog
+    cd myblog
+    
+    # get a template to start
+    git clone git://github.com/nfjinjing/panda-template.git db
+    
+    # manually adjust path information for lighttpd
+    # edit first 6 lines of app/lighttpd/lighttpd.conf to match your path
+    
+    # manual staging
+    ln -s db/public public
+    
+    # run
+    kibro start
+    
+I'm heavily using the [MPS](http://github.com/nfjinjing/mps/tree/master ) package which introduces things like
+
+    reject, join, belongs_to, match, gsub
+    
+and so on.
+    
