diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,94 @@
+Version 0.10.4 released 30 Jun 2014
+
+*   Updated package bounds for happstack (#382), pandoc, blaze-html,
+    network.
+
+*   Display EPS as image, not code.
+
+*   Fixed recent activity page for binary files (Sergey Koposov).
+
+*   Use normal spaces instead of nbsp in activity page (Sergey Koposov).
+
+*   Display a delete link next to uploads in file list (rekado).
+
+*   Change _search to use HTTP GET, so searches can be linked
+    and refreshed (Joe Hillenbrand).
+
+*   Document mod_proxy_html setting in README.  Added a mod_proxy_html
+    configuration directive to insert a DOCTYPE string (Johann Visagie).
+
+*   Added new template variables `isdiscusspage`, `isarticleUrl`,
+    `discussionUrl`.  This makes it possible to treat discussion pages
+    specially in templates, and insert appropriate links (Shane O'Brien).
+
+*   Added template variables `articlename`, `discussionname`,
+    `isarticlepage` (Shane O'Brien).
+
+*   Added redirects (#233).  You can now create a redirect page by adding
+    a `redirect` field to the metadata of a page (Shane O'Brien).
+
+    - When a user visits a redirect page, they are redirected to the
+      destination page.
+    - At the destination page, a message is displayed telling the user
+      that they have been redirected from the source page. A link is
+      provided back to the source page, with a parameter to disable the
+      redirect (so that it can be edited).
+    - Gitit will detects circular redirects and explain to the user
+      what is going on in such cases.
+
+*   Added "search for pages containing..." option to `createPage`.
+    Changed "page not found" page to give the option of searching for
+    the page name or creating a page with that name (Shane O'Brien).
+
+*   Set `pgTitle` in `showDiff` (Shane O'Brien).
+
+*   Made the default "since" for the activity page configurable
+    (Shane O'Brien).
+
+*   Only set the `tabs` template variable if there are tabs (Shane O'Brien).
+
+*   Removed access question from password reset form. It's only
+    needed for the register form (Shane O'Brien).
+
+*   Added `for` attribute to all labels on forms (Shane O'Brien).
+
+*   Updated `pageToString` to use new metadata format (Shane O'Brien).
+
+*   Handlers: Fixed duplicate function defn for `fileAnchor`.
+
+*   Added `Org` and `BocBook` to `PageType` (API change).  Pages
+    may now be written in Ord mode or DocBook syntax.
+
+*   Allow multiple categories, separated by commas,
+    in a `_category` URL (Caleb McDaniel).  The pages in all listed
+    categories will be returned.
+
+*   Added filter links for `_category` pages (Cabel McDaniel).
+
+*   Fixed image exports in Docx, RTF, slides, PDF (#399, #353).
+
+*   Restored inline syntax highlighting.
+
+*   Fixed highlighting in exports (#356).
+
+*   Added `ICML` and `beamer` as export formats (#391).
+
+*   Added github-style backgrounds to code blocks (Joe Hillenbrand).
+
+*   Lighter heading border (like wikimedia) (Joe Hillenbrand).
+
+*   Fixed links on activity page (Shane O'Brien).
+
+*   Added markup help for Textile, Org, DocBook (#434).
+
+*   Modified plugins/Subst.hs to work with latest pandoc (Tianyi Cui).
+
+*   Fixed wiki links when `base-url` is empty and `absolute-urls` yes
+    (Tianyi Cui).
+
+*   README:  document that changes to templates require a restart (Raphael).
+
+
 Version 0.10.3.1 released 19 Mar 2013
 
 *   Fixed filename encoding problem affecting caching,
diff --git a/Network/Gitit.hs b/Network/Gitit.hs
--- a/Network/Gitit.hs
+++ b/Network/Gitit.hs
@@ -171,7 +171,7 @@
     guardBareBase >> getWikiBase >>= \b -> movedPermanently (b ++ "/") (toResponse ())
   , dir "_activity" showActivity
   , dir "_go"       goToPage
-  , dir "_search"   searchResults
+  , method GET >> dir "_search"   searchResults
   , dir "_upload"   $  do guard =<< return . uploadsAllowed =<< getConfig
                           msum [ method GET  >> authenticate ForModify uploadForm
                                  , method POST >> authenticate ForModify uploadFile ]
diff --git a/Network/Gitit/Authentication.hs b/Network/Gitit/Authentication.hs
--- a/Network/Gitit/Authentication.hs
+++ b/Network/Gitit/Authentication.hs
@@ -77,7 +77,7 @@
 resetPasswordRequestForm :: Params -> Handler
 resetPasswordRequestForm _ = do
   let passwordForm = gui "" ! [identifier "resetPassword"] << fieldset <<
-              [ label << "Username: "
+              [ label ! [thefor "username"] << "Username: "
               , textfield "username" ! [size "20", intAttr "tabindex" 1], stringToHtml " "
               , submit "resetPassword" "Reset Password" ! [intAttr "tabindex" 2]]
   cfg <- getConfig
@@ -215,9 +215,11 @@
   dest <- case pDestination params of
                 ""  -> getReferer
                 x   -> return x
-  let accessQ = case accessQuestion cfg of
+  let accessQ = case mbUser of
+            Just _ -> noHtml
+            Nothing -> case accessQuestion cfg of
                       Nothing          -> noHtml
-                      Just (prompt, _) -> label << prompt +++ br +++
+                      Just (prompt, _) -> label ! [thefor "accessCode"] << prompt +++ br +++
                                           X.password "accessCode" ! [size "15", intAttr "tabindex" 1]
                                           +++ br
   let captcha = if useRecaptcha cfg
@@ -227,12 +229,13 @@
                       Nothing    -> ""
                       Just user  -> field user
   let userNameField = case mbUser of
-                      Nothing    -> label <<
+                      Nothing    -> label ! [thefor "username"] <<
                                      "Username (at least 3 letters or digits):"
                                     +++ br +++
                                     textfield "username" ! [size "20", intAttr "tabindex" 2] +++ br
-                      Just user  -> label << ("Username (cannot be changed): "
-                                               ++ uUsername user) +++ br
+                      Just user  -> label ! [thefor "username"] <<
+                                    ("Username (cannot be changed): " ++ uUsername user)
+                                    +++ br
   let submitField = case mbUser of
                       Nothing    -> submit "register" "Register"
                       Just _     -> submit "resetPassword" "Reset Password"
@@ -240,17 +243,18 @@
   return $ gui "" ! [identifier "loginForm"] << fieldset <<
             [ accessQ
             , userNameField
-            , label << "Email (optional, will not be displayed on the Wiki):"
+            , label ! [thefor "email"] << "Email (optional, will not be displayed on the Wiki):"
             , br
             , textfield "email" ! [size "20", intAttr "tabindex" 3, value (initField uEmail)], br
             , textfield "full_name_1" ! [size "20", theclass "req"]
-            , label << ("Password (at least 6 characters," ++
+            , label ! [thefor "password"]
+                    << ("Password (at least 6 characters," ++
                         " including at least one non-letter):")
             , br
             , X.password "password" ! [size "20", intAttr "tabindex" 4]
             , stringToHtml " "
             , br
-            , label << "Confirm Password:"
+            , label ! [thefor "password2"] << "Confirm Password:"
             , br
             , X.password "password2" ! [size "20", intAttr "tabindex" 5]
             , stringToHtml " "
@@ -279,9 +283,11 @@
   let optionalTests Register =
           [(taken, "Sorry, that username is already taken.")]
       optionalTests ResetPassword = []
-  let isValidAccessCode = case accessQuestion cfg of
-        Nothing           -> True
-        Just (_, answers) -> accessCode `elem` answers
+  let isValidAccessCode = case validationType of
+        ResetPassword -> True
+        Register -> case accessQuestion cfg of
+            Nothing           -> True
+            Just (_, answers) -> accessCode `elem` answers
   let isValidEmail e = length (filter (=='@') e) == 1
   peer <- liftM (fst . rqPeer) askRq
   captchaResult <-
@@ -332,10 +338,10 @@
   base' <- getWikiBase
   return $ gui (base' ++ "/_login") ! [identifier "loginForm"] <<
     fieldset <<
-      [ label << "Username "
+      [ label ! [thefor "username"] << "Username "
       , textfield "username" ! [size "15", intAttr "tabindex" 1]
       , stringToHtml " "
-      , label << "Password "
+      , label ! [thefor "password"] << "Password "
       , X.password "password" ! [size "15", intAttr "tabindex" 2]
       , stringToHtml " "
       , textfield "destination" ! [thestyle "display: none;", value dest]
diff --git a/Network/Gitit/Config.hs b/Network/Gitit/Config.hs
--- a/Network/Gitit/Config.hs
+++ b/Network/Gitit/Config.hs
@@ -109,6 +109,7 @@
       cfPDFExport <- get cp "DEFAULT" "pdf-export"
       cfPandocUserData <- get cp "DEFAULT" "pandoc-user-data"
       cfXssSanitize <- get cp "DEFAULT" "xss-sanitize"
+      cfRecentActivityDays <- get cp "DEFAULT" "recent-activity-days"
       let (pt, lhs) = parsePageType cfDefaultPageType
       let markupHelpFile = show pt ++ if lhs then "+LHS" else ""
       markupHelpPath <- liftIO $ getDataFileName $ "data" </> "markupHelp" </> markupHelpFile
@@ -202,6 +203,7 @@
                                     then Nothing
                                     else Just cfPandocUserData
         , xssSanitize          = cfXssSanitize
+        , recentActivityDays   = cfRecentActivityDays
         }
   case config' of
         Left (ParseError e, e') -> error $ "Parse error: " ++ e ++ "\n" ++ e'
diff --git a/Network/Gitit/ContentTransformer.hs b/Network/Gitit/ContentTransformer.hs
--- a/Network/Gitit/ContentTransformer.hs
+++ b/Network/Gitit/ContentTransformer.hs
@@ -72,23 +72,28 @@
 import Control.Exception (throwIO, catch)
 import Control.Monad.State
 import Control.Monad.Reader (ask)
+import Data.Foldable (traverse_)
+import Data.List (stripPrefix)
 import Data.Maybe (isNothing, mapMaybe)
 import Network.Gitit.Cache (lookupCache, cacheContents)
 import Network.Gitit.Export (exportFormats)
-import Network.Gitit.Framework
+import Network.Gitit.Framework hiding (uriPath)
 import Network.Gitit.Layout
 import Network.Gitit.Page (stringToPage)
 import Network.Gitit.Server
 import Network.Gitit.State
 import Network.Gitit.Types
+import Network.HTTP (urlDecode)
 import Network.URI (isUnescapedInURI)
 import Network.URL (encString)
 import Prelude hiding (catch)
 import System.FilePath
+import qualified Text.Pandoc.Builder as B
 import Text.HTML.SanitizeXSS (sanitizeBalance)
 import Text.Highlighting.Kate
 import Text.Pandoc hiding (MathML, WebTeX, MathJax)
 import Text.XHtml hiding ( (</>), dir, method, password, rev )
+import Text.XHtml.Strict (stringToHtmlString)
 #if MIN_VERSION_blaze_html(0,5,0)
 import Text.Blaze.Html.Renderer.String as Blaze ( renderHtml )
 #else
@@ -97,9 +102,11 @@
 import qualified Data.Text as T
 import qualified Data.Set as Set
 import qualified Data.ByteString as S (concat)
+import qualified Data.ByteString.Char8 as SC (unpack)
 import qualified Data.ByteString.Lazy as L (toChunks, fromChunks)
 import qualified Data.FileStore as FS
 import qualified Text.Pandoc as Pandoc
+import Text.URI (parseURI, URI(..), uriQueryItems)
 
 --
 -- ContentTransformer runners
@@ -207,12 +214,14 @@
                   (rawContents >>=
                    maybe mzero return >>=
                    contentsToPage >>=
-                   pageToWikiPandoc >>=
-                   addMathSupport >>=
-                   pandocToHtml >>=
-                   wikiDivify >>=
-                   applyWikiTemplate >>=
-                   cacheHtml)
+                   handleRedirects >>=
+                   either return
+                     (pageToWikiPandoc >=>
+                      addMathSupport >=>
+                      pandocToHtml >=>
+                      wikiDivify >=>
+                      applyWikiTemplate >=>
+                      cacheHtml))
 
 -- | Responds with highlighted source code in a wiki
 -- page template.  Uses the cache when possible and
@@ -331,6 +340,157 @@
                              , ctxMeta = pageMeta page' }
   return $ readerFor (pageFormat page') (pageLHS page') (pageText page')
 
+-- | Detects if the page is a redirect page and handles accordingly. The exact
+-- behaviour is as follows:
+--
+-- If the page is /not/ a redirect page (the most common case), then check the
+-- referer to see if the client came to this page as a result of a redirect
+-- from another page. If so, then add a notice to the messages to notify the
+-- user that they were redirected from another page, and provide a link back
+-- to the original page, with an extra parameter to disable redirection
+-- (e.g., to allow the original page to be edited).
+--
+-- If the page /is/ a redirect page, then check the query string for the
+-- @redirect@ parameter. This can modify the behaviour of the redirect as
+-- follows:
+--
+-- 1. If the @redirect@ parameter is unset, then check the referer to see if
+--    client came to this page as a result of a redirect from another page. If
+--    so, then do not redirect, and add a notice to the messages explaining
+--    that this page is a redirect page, that would have redirected to the
+--    destination given in the metadata (and provide a link thereto), but this
+--    was stopped because a double-redirect was detected. This is a simple way
+--    to prevent cyclical redirects and other abuses enabled by redirects.
+--    redirect to the same page. If the client did /not/ come to this page as
+--    a result of a redirect, then redirect back to the same page, except with
+--    the redirect parameter set to @\"yes\"@.
+--
+-- 2. If the @redirect@ parameter is set to \"yes\", then redirect to the
+--    destination specificed in the metadata. This uses a client-side (meta
+--    refresh + javascript backup) redirect to make sure the referer is set to
+--    this URL.
+--
+-- 3. If the @redirect@ parameter is set to \"no\", then do not redirect, but
+--    add a notice to the messages that this page /would/ have redirected to
+--    the destination given in the metadata had it not been disabled, and
+--    provide a link to the destination given in the metadata. This behaviour
+--    is the @revision@ parameter is present in the query string.
+handleRedirects :: Page -> ContentTransformer (Either Response Page)
+handleRedirects page = case lookup "redirect" (pageMeta page) of
+    Nothing -> isn'tRedirect
+    Just destination -> isRedirect destination
+  where
+    addMessage message = modifyContext $ \context -> context
+        { ctxLayout = (ctxLayout context)
+            { pgMessages = pgMessages (ctxLayout context) ++ [message]
+            }
+        }
+    redirectedFrom source = do
+        (url, html) <- processSource source
+        return $ concat
+            [ "Redirected from <a href=\""
+            , url
+            , "?redirect=no\" title=\"Go to original page\">"
+            , html
+            , "</a>"
+            ]
+    doubleRedirect source destination = do
+        (url, html) <- processSource source
+        (url', html') <- processDestination destination
+        return $ concat
+            [ "This page normally redirects to <a href=\""
+            , url'
+            , "\" title=\"Continue to destination\">"
+            , html'
+            , "</a>, but as you were already redirected from <a href=\""
+            , url
+            , "?redirect=no\" title=\"Go to original page\">"
+            , html
+            , "</a>"
+            , ", this was stopped to prevent a double-redirect."
+            ]
+    cancelledRedirect destination = do
+        (url', html') <- processDestination destination
+        return $ concat
+            [ "This page redirects to <a href=\""
+            , url'
+            , "\" title=\"Continue to destination\">"
+            , html'
+            , "</a>."
+            ]
+    processSource source = do
+        base' <- getWikiBase
+        let url = stringToHtmlString $ base' ++ urlForPage source
+        let html = stringToHtmlString source
+        return (url, html)
+    processDestination destination = do
+        base' <- getWikiBase
+        let (page', fragment) = break (== '#') destination
+        let url = stringToHtmlString $ concat
+             [ base'
+             , urlForPage page'
+             , fragment
+             ]
+        let html = stringToHtmlString page'
+        return (url, html)
+    getSource = do
+        cfg <- lift getConfig
+        base' <- getWikiBase
+        request <- askRq
+        return $ do
+            uri <- getHeader "referer" request >>= parseURI . SC.unpack
+            let params = uriQueryItems uri
+            redirect' <- lookup "redirect" params
+            guard $ redirect' == "yes"
+            path' <- stripPrefix (base' ++ "/") (uriPath uri)
+            let path'' = if null path' then frontPage cfg else urlDecode path'
+            guard $ isPage path''
+            return path''
+    withBody = setContentType "text/html; charset=utf-8" . toResponse
+    isn'tRedirect = do
+        getSource >>= traverse_ (redirectedFrom >=> addMessage)
+        return (Right page)
+    isRedirect destination = do
+        params <- getParams
+        case maybe (pRedirect params) (\_ -> Just False) (pRevision params) of
+             Nothing -> do
+                source <- getSource
+                case source of
+                     Just source' -> do
+                        doubleRedirect source' destination >>= addMessage
+                        return (Right page)
+                     Nothing -> fmap Left $ do
+                        base' <- getWikiBase
+                        let url' = concat
+                             [ base'
+                             , urlForPage (pageName page)
+                             , "?redirect=yes"
+                             ]
+                        lift $ seeOther url' $ withBody $ concat
+                            [ "<!doctype html><html><head><title>307 Redirect"
+                            , "</title></head><body><p>You are being <a href=\""
+                            , stringToHtmlString url'
+                            , "\">redirected</a>.</body></p></html>"
+                            ]
+             Just True -> fmap Left $ do
+                (url', html') <- processDestination destination
+                lift $ ok $ withBody $ concat
+                    [ "<!doctype html><html><head><title>Redirecting to "
+                    , html'
+                    , "</title><meta http-equiv=\"refresh\" contents=\"0; url="
+                    , url'
+                    , "\" /><script type=\"text/javascript\">window.location=\""
+                    , url'
+                    , "\"</script></head><body><p>Redirecting to <a href=\""
+                    , url'
+                    , "\">"
+                    , html'
+                    , "</a>...</p></body></html>"
+                    ]
+             Just False -> do
+                cancelledRedirect destination >>= addMessage
+                return (Right page)
+
 -- | Converts contents of page file to Page object.
 contentsToPage :: String -> ContentTransformer Page
 contentsToPage s = do
@@ -358,6 +518,7 @@
                                  _      -> JsMath (Just $ base' ++
                                                       "/js/jsMath/easy/load.js")
                       , writerTableOfContents = toc
+                      , writerHighlight = True
                       , writerExtensions = if bird
                                               then Set.insert
                                                    Ext_literate_haskell
@@ -452,8 +613,8 @@
 addPageTitleToPandoc title' (Pandoc _ blocks) = do
   updateLayout $ \layout -> layout{ pgTitle = title' }
   return $ if null title'
-              then Pandoc (Meta [] [] []) blocks
-              else Pandoc (Meta [Str title'] [] []) blocks
+              then Pandoc nullMeta blocks
+              else Pandoc (B.setMeta "title" (B.str title') nullMeta) blocks
 
 -- | Adds javascript links for math support.
 addMathSupport :: a -> ContentTransformer a
@@ -516,6 +677,8 @@
        LaTeX    -> readLaTeX defPS
        HTML     -> readHtml defPS
        Textile  -> readTextile defPS
+       Org      -> readOrg defPS
+       DocBook  -> readDocBook defPS
 
 wikiLinksTransform :: Pandoc -> PluginM Pandoc
 wikiLinksTransform pandoc
@@ -525,7 +688,7 @@
 -- | Convert links with no URL to wikilinks.
 convertWikiLinks :: Config -> Inline -> Inline
 convertWikiLinks cfg (Link ref ("", "")) | useAbsoluteUrls cfg =
-  Link ref (baseUrl cfg </> inlinesToURL ref, "Go to wiki page")
+  Link ref ("/" </> baseUrl cfg </> inlinesToURL ref, "Go to wiki page")
 convertWikiLinks _cfg (Link ref ("", "")) =
   Link ref (inlinesToURL ref, "Go to wiki page")
 convertWikiLinks _cfg x = x
@@ -553,9 +716,10 @@
                LineBreak               -> " "
                Math DisplayMath s      -> "$$" ++ s ++ "$$"
                Math InlineMath s       -> "$" ++ s ++ "$"
-               RawInline "tex" s       -> s
+               RawInline (Format "tex") s -> s
                RawInline _ _           -> ""
                Link xs _               -> concatMap go xs
                Image xs _              -> concatMap go xs
                Note _                  -> ""
+               Span _ xs               -> concatMap go xs
 
diff --git a/Network/Gitit/Export.hs b/Network/Gitit/Export.hs
--- a/Network/Gitit/Export.hs
+++ b/Network/Gitit/Export.hs
@@ -22,37 +22,32 @@
 module Network.Gitit.Export ( exportFormats ) where
 import Text.Pandoc hiding (HTMLMathMethod(..))
 import qualified Text.Pandoc as Pandoc
+import Text.Pandoc.PDF (makePDF)
 import Text.Pandoc.SelfContained as SelfContained
-import Text.Pandoc.Shared (escapeStringUsing, readDataFileUTF8)
+import Text.Pandoc.Shared (readDataFileUTF8)
 import Network.Gitit.Server
 import Network.Gitit.Framework (pathForPage, getWikiBase)
-import Network.Gitit.Util (withTempDir, readFileUTF8)
 import Network.Gitit.State (getConfig)
 import Network.Gitit.Types
 import Network.Gitit.Cache (cacheContents, lookupCache)
 import Control.Monad.Trans (liftIO)
-import Control.Monad (unless, when)
+import Control.Monad (unless)
 import Text.XHtml (noHtml)
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
-import Data.ByteString.Lazy.UTF8 (fromString)
-import System.FilePath ((<.>), (</>), takeDirectory)
+import Data.ByteString.Lazy.UTF8 (fromString, toString)
+import System.FilePath ((</>), takeDirectory)
 import Control.Exception (throwIO)
-import System.Environment (getEnvironment)
-import System.Exit (ExitCode(..))
-import System.IO (openTempFile)
-import System.Directory (getCurrentDirectory, setCurrentDirectory, removeFile,
-                         doesFileExist)
-import System.Process (runProcess, waitForProcess)
-import Codec.Binary.UTF8.String (encodeString)
+import System.Directory (doesFileExist)
 import Text.HTML.SanitizeXSS
 import Text.Pandoc.Writers.RTF (writeRTFWithEmbeddedImages)
 import qualified Data.Text as T
 import Data.List (isPrefixOf)
+import Text.Highlighting.Kate (styleToCss, pygments)
 import Paths_gitit (getDataFileName)
 
 defaultRespOptions :: WriterOptions
-defaultRespOptions = def { writerStandalone = True }
+defaultRespOptions = def { writerStandalone = True, writerHighlight = True }
 
 respond :: String
         -> String
@@ -74,11 +69,10 @@
   template <- case template' of
                   Right t  -> return t
                   Left e   -> liftIO $ throwIO e
-  doc' <- if ext `elem` ["odt","pdf","epub","docx","rtf"]
+  doc' <- if ext `elem` ["odt","pdf","beamer","epub","docx","rtf"]
              then fixURLs page doc
              else return doc
   respond mimetype ext (fn opts{writerTemplate = template
-                               ,writerSourceDirectory = repositoryPath cfg
                                ,writerUserDataDir = pandocUserData cfg})
           page doc'
 
@@ -132,9 +126,8 @@
                   else return ""
     let h = writeHtmlString opts'{
                 writerVariables =
-                  ("body",body''):("dzslides-core",dzcore):variables'
+                  ("body",body''):("dzslides-core",dzcore):("highlighting-css",pygmentsCss):variables'
                ,writerTemplate = template
-               ,writerSourceDirectory = repositoryPath cfg
                ,writerUserDataDir = pandocUserData cfg
                } (Pandoc meta [])
     h' <- liftIO $ makeSelfContained (pandocUserData cfg) h
@@ -183,6 +176,10 @@
 respondOrg = respondS "org" "text/plain; charset=utf-8" ""
   writeOrg defaultRespOptions
 
+respondICML :: String -> Pandoc -> Handler
+respondICML = respondS "icml" "application/xml; charset=utf-8" ""
+  writeICML defaultRespOptions
+
 respondTextile :: String -> Pandoc -> Handler
 respondTextile = respondS "textile" "text/plain; charset=utf-8" ""
   writeTextile defaultRespOptions
@@ -208,23 +205,8 @@
   "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
   "docx" writeDocx defaultRespOptions
 
---- | Run shell command and return error status.  Assumes
--- UTF-8 locale. Note that this does not actually go through \/bin\/sh!
-runShellCommand :: FilePath                     -- ^ Working directory
-                -> Maybe [(String, String)]     -- ^ Environment
-                -> String                       -- ^ Command
-                -> [String]                     -- ^ Arguments
-                -> IO ExitCode
-runShellCommand workingDir environment command optionList = do
-  (errPath, err) <- openTempFile workingDir "err"
-  hProcess <- runProcess (encodeString command) (map encodeString optionList)
-               (Just workingDir) environment Nothing (Just err) (Just err)
-  status <- waitForProcess hProcess
-  removeFile errPath
-  return status
-
-respondPDF :: String -> Pandoc -> Handler
-respondPDF page old_pndc = fixURLs page old_pndc >>= \pndc -> do
+respondPDF :: Bool -> String -> Pandoc -> Handler
+respondPDF useBeamer page old_pndc = fixURLs page old_pndc >>= \pndc -> do
   cfg <- getConfig
   unless (pdfExport cfg) $ error "PDF export disabled"
   let cacheName = pathForPage page ++ ".export.pdf"
@@ -232,38 +214,26 @@
                then lookupCache cacheName
                else return Nothing
   pdf' <- case cached of
-            Just (_modtime, bs) -> return $ Right (False, L.fromChunks [bs])
-            Nothing -> liftIO $ withTempDir "gitit-tmp-pdf" $ \tempdir -> do
-              template' <- liftIO $ getDefaultTemplate (pandocUserData cfg) "latex"
-              template  <- either throwIO return template'
+            Just (_modtime, bs) -> return $ Right $ L.fromChunks [bs]
+            Nothing -> do
+              template' <- liftIO $ getDefaultTemplate (pandocUserData cfg)
+                                  $ if useBeamer then "beamer" else "latex"
+              template  <- liftIO $ either throwIO return template'
               let toc = tableOfContents cfg
-              let latex = writeLaTeX defaultRespOptions{writerTemplate = template
-                                                       ,writerTableOfContents = toc} pndc
-              let tempfile = "export" <.> "tex"
-              curdir <- getCurrentDirectory
-              setCurrentDirectory tempdir
-              writeFile tempfile latex
-              -- run pdflatex twice to get the references and toc right
-              let cmd = "pdflatex"
-              oldEnv <- getEnvironment
-              let env = Just $ ("TEXINPUTS",".:" ++
-                               escapeStringUsing [(' ',"\\ "),('"',"\\\"")]
-                               (curdir </> repositoryPath cfg) ++ ":") : oldEnv
-              let opts = ["-interaction=batchmode", "-no-shell-escape", tempfile]
-              _ <- runShellCommand tempdir env cmd opts
-              canary <- runShellCommand tempdir env cmd opts
-              setCurrentDirectory curdir -- restore original location
-              case canary of
-                  ExitSuccess   -> do pdfBS <- L.readFile (tempdir </> "export" <.> "pdf")
-                                      return $ Right (useCache cfg, pdfBS)
-                  ExitFailure n -> do l <- readFileUTF8 (tempdir </> "export" <.> "log")
-                                      return $ Left (n, l)
+              res <- liftIO $ makePDF "pdflatex" writeLaTeX
+                         defaultRespOptions{writerTemplate = template
+                                           ,writerSourceURL = Just $ baseUrl cfg
+                                           ,writerTableOfContents = toc
+                                           ,writerBeamer = useBeamer} pndc
+              return res
   case pdf' of
-       Left (n,logOutput) -> simpleErrorHandler ("PDF creation failed with code: " ++
-                               show n ++ "\n" ++ logOutput)
-       Right (needsCaching, pdfBS) -> do
-              when needsCaching $
-                 cacheContents cacheName $ B.concat . L.toChunks $ pdfBS
+       Left logOutput -> simpleErrorHandler ("PDF creation failed:\n"
+                           ++ toString logOutput)
+       Right pdfBS -> do
+              case cached of
+                Nothing ->
+                     cacheContents cacheName $ B.concat . L.toChunks $ pdfBS
+                _ -> return ()
               ok $ setContentType "application/pdf" $ setFilename (page ++ ".pdf") $
                         (toResponse noHtml) {rsBody = pdfBS}
 
@@ -300,7 +270,9 @@
 
 exportFormats :: Config -> [(String, String -> Pandoc -> Handler)]
 exportFormats cfg = if pdfExport cfg
-                       then ("PDF", respondPDF) : rest
+                       then ("PDF", respondPDF False) :
+                            ("Beamer", respondPDF True) :
+                            rest
                        else rest
    where rest = [ ("LaTeX",     respondLaTeX)     -- (description, writer)
                 , ("ConTeXt",   respondConTeXt)
@@ -310,6 +282,7 @@
                 , ("Plain text",respondPlain)
                 , ("MediaWiki", respondMediaWiki)
                 , ("Org-mode",  respondOrg)
+                , ("ICML",      respondICML)
                 , ("Textile",   respondTextile)
                 , ("AsciiDoc",  respondAsciiDoc)
                 , ("Man page",  respondMan)
@@ -319,5 +292,8 @@
                 , ("S5",        respondSlides "s5" S5Slides)
                 , ("EPUB",      respondEPUB)
                 , ("ODT",       respondODT)
-                , ("Docx",      respondDocx)
+                , ("DOCX",      respondDocx)
                 , ("RTF",       respondRTF) ]
+
+pygmentsCss :: String
+pygmentsCss = styleToCss pygments
diff --git a/Network/Gitit/Framework.hs b/Network/Gitit/Framework.hs
--- a/Network/Gitit/Framework.hs
+++ b/Network/Gitit/Framework.hs
@@ -269,8 +269,9 @@
 isSourceCode :: String -> Bool
 isSourceCode path' =
   let langs = languagesByFilename $ takeFileName path'
-  in  not (null langs || takeExtension path' == ".svg")
-                         -- allow svg to be served as image
+      ext = takeExtension path'
+  in  not (null langs || ext == ".svg" || ext == ".eps")
+                         -- allow svg or eps to be served as image
 
 -- | Returns encoded URL path for the page with the given name, relative to
 -- the wiki base.
diff --git a/Network/Gitit/Handlers.hs b/Network/Gitit/Handlers.hs
--- a/Network/Gitit/Handlers.hs
+++ b/Network/Gitit/Handlers.hs
@@ -69,7 +69,8 @@
 import Network.Gitit.State
 import Text.XHtml hiding ( (</>), dir, method, password, rev )
 import qualified Text.XHtml as X ( method )
-import Data.List (intersperse, nub, sortBy, find, isPrefixOf, inits, sort)
+import Data.List (intercalate, intersperse, delete, nub, sortBy, find, isPrefixOf, inits, sort, (\\))
+import Data.List.Split (wordsBy)
 import Data.Maybe (fromMaybe, mapMaybe, isJust, catMaybes)
 import Data.Ord (comparing)
 import Data.Char (toLower, isSpace)
@@ -83,13 +84,14 @@
 import System.Log.Logger (logM, Priority(..))
 
 handleAny :: Handler
-handleAny = uriRest $ \uri ->
+handleAny = withData $ \(params :: Params) -> uriRest $ \uri ->
   let path' = uriPath uri
   in  do fs <- getFileStore
+         let rev = pRevision params
          mimetype <- getMimeTypeForExtension
                       (takeExtension path')
          res <- liftIO $ try
-                (retrieve fs path' Nothing :: IO B.ByteString)
+                (retrieve fs path' rev :: IO B.ByteString)
          case res of
                 Right contents -> ignoreFilters >>  -- don't compress
                                   (ok $ setContentType mimetype $
@@ -141,10 +143,18 @@
                                     , pgTabs = []
                                     , pgTitle = "Create " ++ page ++ "?"
                                     } $
-                    p << [ stringToHtml ("There is no page '" ++ page ++
-                              "'.  You may create the page by "),
-                            anchor ! [href $ base' ++ "/_edit" ++ urlForPage page] <<
-                              "clicking here." ]
+                    (p << stringToHtml
+                        ("There is no page named '" ++ page ++ "'. You can:"))
+                        +++
+                    (unordList $
+                      [ anchor !
+                            [href $ base' ++ "/_edit" ++ urlForPage page] <<
+                              ("Create the page '" ++ page ++ "'")
+                      , anchor !
+                            [href $ base' ++ "/_search?" ++
+                                (urlEncodeVars [("patterns", page)])] <<
+                              ("Search for pages containing the text '" ++
+                                page ++ "'")])
 
 uploadForm :: Handler
 uploadForm = withData $ \(params :: Params) -> do
@@ -153,18 +163,18 @@
   let logMsg = pLogMsg params
   let upForm = form ! [X.method "post", enctype "multipart/form-data"] <<
        fieldset <<
-       [ p << [label << "File to upload:"
+       [ p << [label ! [thefor "file"] << "File to upload:"
               , br
               , afile "file" ! [value origPath] ]
-       , p << [ label << "Name on wiki, including extension"
+       , p << [ label ! [thefor "wikiname"] << "Name on wiki, including extension"
               , noscript << " (leave blank to use the same filename)"
               , stringToHtml ":"
               , br
               , textfield "wikiname" ! [value wikiname]
               , primHtmlChar "nbsp"
               , checkbox "overwrite" "yes"
-              , label << "Overwrite existing file" ]
-       , p << [ label << "Description of content or changes:"
+              , label ! [thefor "overwrite"] << "Overwrite existing file" ]
+       , p << [ label ! [thefor "logMsg"] << "Description of content or changes:"
               , br
               , textfield "logMsg" ! [size "60", value logMsg]
               , submit "upload" "Upload" ]
@@ -377,10 +387,12 @@
 
 showActivity :: Handler
 showActivity = withData $ \(params :: Params) -> do
+  cfg <- getConfig
   currTime <- liftIO getCurrentTime
-  let oneMonthAgo = addUTCTime (-60 * 60 * 24 * 30) currTime
+  let defaultDaysAgo = fromIntegral (recentActivityDays cfg)
+  let daysAgo = addUTCTime (defaultDaysAgo * (-60) * 60 * 24) currTime
   let since = case pSince params of
-                   Nothing -> Just oneMonthAgo
+                   Nothing -> Just daysAgo
                    Just t  -> Just t
   let forUser = pForUser params
   fs <- getFileStore
@@ -392,14 +404,13 @@
   let fileFromChange (Added f)    = f
       fileFromChange (Modified f) = f
       fileFromChange (Deleted f)  = f
-  let dropDotPage file = if isPageFile file
-                            then dropExtension file
-                            else file
+
   base' <- getWikiBase
-  let fileAnchor revis file =
-        anchor ! [href $ base' ++ "/_diff" ++ urlForPage file ++ "?to=" ++ revis] << file
-  let filesFor changes revis = intersperse (primHtmlChar "nbsp") $
-        map (fileAnchor revis . dropDotPage . fileFromChange) changes
+  let fileAnchor revis file = if isPageFile file
+        then anchor ! [href $ base' ++ "/_diff" ++ urlForPage (dropExtension file) ++ "?to=" ++ revis] << dropExtension file
+        else anchor ! [href $ base' ++ urlForPage file ++ "?revision=" ++ revis] << file
+  let filesFor changes revis = intersperse (stringToHtml " ") $
+        map (fileAnchor revis . fileFromChange) changes
   let heading = h1 << ("Recent changes by " ++ fromMaybe "all users" forUser)
   let revToListItem rev = li <<
         [ thespan ! [theclass "date"] << (show $ revDateTime rev)
@@ -464,7 +475,8 @@
                                           pgMessages = pMessages params,
                                           pgTabs = DiffTab :
                                                    pgTabs defaultPageLayout,
-                                          pgSelectedTab = DiffTab
+                                          pgSelectedTab = DiffTab,
+                                          pgTitle = page
                                           }
                                        htmlDiff
 
@@ -523,7 +535,7 @@
                    , textarea ! (readonly ++ [cols "80", name "editedText",
                                   identifier "editedText"]) << raw
                    , br
-                   , label << "Description of changes:"
+                   , label ! [thefor "logMsg"] << "Description of changes:"
                    , br
                    , textfield "logMsg" ! (readonly ++ [value logMsg])
                    , submit "update" "Save"
@@ -599,7 +611,7 @@
   if pConfirm params && (file == page || file == page <.> "page")
      then do
        fs <- getFileStore
-       liftIO $ delete fs file author descrip
+       liftIO $ Data.FileStore.delete fs file author descrip
        seeOther (base' ++ "/") $ toResponse $ p << "File deleted"
      else seeOther (base' ++ urlForPage page) $ toResponse $ p << "Not deleted"
 
@@ -674,8 +686,10 @@
         li ! [theclass "page"  ] <<
           anchor ! [href $ base' ++ urlForPage (prefix ++ dropExtension f)] <<
             dropExtension f
-      fileLink (FSFile f) =
-        li ! [theclass "upload"] << anchor ! [href $ base' ++ urlForPage (prefix ++ f)] << f
+      fileLink (FSFile f) = li ! [theclass "upload"] << concatHtml
+        [ anchor ! [href $ base' ++ urlForPage (prefix ++ f)] << f
+        , anchor ! [href $ base' ++ "_delete" ++ urlForPage (prefix ++ f)] << "(delete)"
+        ]
       fileLink (FSDirectory f) =
         li ! [theclass "folder"] <<
           anchor ! [href $ base' ++ urlForPage (prefix ++ f) ++ "/"] << f
@@ -694,30 +708,44 @@
 -- more sophisticated searching options to filestore.
 categoryPage :: Handler
 categoryPage = do
-  category <- getPath
+  path' <- getPath
   cfg <- getConfig
+  let pcategories = wordsBy (==',') path'
   let repoPath = repositoryPath cfg
-  let categoryDescription = "Category: " ++ category
+  let categoryDescription = "Category: " ++ (intercalate " + " pcategories)
   fs <- getFileStore
   files <- liftIO $ index fs
   let pages = filter (\f -> isPageFile f && not (isDiscussPageFile f)) files
   matches <- liftM catMaybes $
              forM pages $ \f -> do
                categories <- liftIO $ readCategories $ repoPath </> f
-               return $ if category `elem` categories
-                           then Just f
+               return $ if all ( `elem` categories) pcategories
+                           then Just (f, categories \\ pcategories)
                            else Nothing
   base' <- getWikiBase
   let toMatchListItem file = li <<
         [ anchor ! [href $ base' ++ urlForPage (dropExtension file)] << dropExtension file ]
-  let htmlMatches = ulist << map toMatchListItem matches
+  let toRemoveListItem cat = li << 
+        [ anchor ! [href $ base' ++
+        (if null (tail pcategories)
+         then "/_categories"
+         else "/_category" ++ urlForPage (intercalate "," $ Data.List.delete cat pcategories)) ]
+        << ("-" ++ cat) ]
+  let toAddListItem cat = li <<
+        [ anchor ! [href $ base' ++
+          "/_category" ++ urlForPage (path' ++ "," ++ cat) ]
+        << ("+" ++ cat) ]
+  let matchList = ulist << map toMatchListItem (fst $ unzip matches) +++
+                  thediv ! [ identifier "categoryList" ] <<
+                  ulist << (++) (map toAddListItem (nub $ concat $ snd $ unzip matches)) 
+                                (map toRemoveListItem pcategories) 
   formattedPage defaultPageLayout{
                   pgPageName = categoryDescription,
                   pgShowPageTools = False,
                   pgTabs = [],
                   pgScripts = ["search.js"],
                   pgTitle = categoryDescription }
-                htmlMatches
+                matchList
 
 categoryListPage :: Handler
 categoryListPage = do
diff --git a/Network/Gitit/Initialize.hs b/Network/Gitit/Initialize.hs
--- a/Network/Gitit/Initialize.hs
+++ b/Network/Gitit/Initialize.hs
@@ -136,6 +136,8 @@
                        HTML     -> writeHtmlString defOpts . toPandoc
                        RST      -> writeRST defOpts . toPandoc
                        Textile  -> writeTextile defOpts . toPandoc
+                       Org      -> writeOrg defOpts . toPandoc
+                       DocBook  -> writeDocbook defOpts . toPandoc
 
     welcomepath <- getDataFileName $ "data" </> "FrontPage" <.> "page"
     welcomecontents <- liftM converter $ readFileUTF8 welcomepath
diff --git a/Network/Gitit/Layout.hs b/Network/Gitit/Layout.hs
--- a/Network/Gitit/Layout.hs
+++ b/Network/Gitit/Layout.hs
@@ -83,6 +83,8 @@
       scriptLink x = script ! [src (prefixedScript x),
         thetype "text/javascript"] << noHtml
       javascriptlinks = renderHtmlFragment $ concatHtml $ map scriptLink scripts
+      article = if isDiscussPage page then drop 1 page else page
+      discussion = '@':article
       tabli tab = if tab == pgSelectedTab layout
                      then li ! [theclass "selected"]
                      else li
@@ -97,8 +99,14 @@
                    setStrAttr "pagetitle" (pgTitle layout) .
                    T.setAttribute "javascripts" javascriptlinks .
                    setStrAttr "pagename" page .
+                   setStrAttr "articlename" article .
+                   setStrAttr "discussionname" discussion .
                    setStrAttr "pageUrl" (urlForPage page) .
+                   setStrAttr "articleUrl" (urlForPage article) .
+                   setStrAttr "discussionUrl" (urlForPage discussion) .
                    setBoolAttr "ispage" (isPage page) .
+                   setBoolAttr "isarticlepage" (isPage page && not (isDiscussPage page)) .
+                   setBoolAttr "isdiscusspage" (isDiscussPage page) .
                    setBoolAttr "pagetools" (pgShowPageTools layout) .
                    setBoolAttr "sitenav" (pgShowSiteNav layout) .
                    maybe id (T.setAttribute "markuphelp") (pgMarkupHelp layout) .
@@ -106,13 +114,13 @@
                    maybe id (T.setAttribute "revision") rev .
                    T.setAttribute "exportbox"
                        (renderHtmlFragment $  exportBox base' cfg page rev) .
-                   T.setAttribute "tabs" (renderHtmlFragment tabs) .
-                   T.setAttribute "messages" (pgMessages layout) .
+                   (if null (pgTabs layout) then id else T.setAttribute "tabs"
+                       (renderHtmlFragment tabs)) .
+                   (\f x xs -> if null xs then x else f xs) (T.setAttribute "messages") id (pgMessages layout) .
                    T.setAttribute "usecache" (useCache cfg) .
                    T.setAttribute "content" (renderHtmlFragment htmlContents) .
                    setBoolAttr "wikiupload" ( uploadsAllowed cfg) $
                    templ
-
 
 
 exportBox :: String -> Config -> String -> Maybe String -> Html
diff --git a/Network/Gitit/Page.hs b/Network/Gitit/Page.hs
--- a/Network/Gitit/Page.hs
+++ b/Network/Gitit/Page.hs
@@ -53,6 +53,7 @@
 import Network.Gitit.Util (trim, splitCategories, parsePageType)
 import Text.ParserCombinators.Parsec
 import Data.Char (toLower)
+import Data.List (intercalate)
 import Data.Maybe (fromMaybe)
 import Data.ByteString.UTF8 (toString)
 import qualified Data.ByteString as B
@@ -134,23 +135,29 @@
       pagelhs    = pageLHS page'
       pagetoc    = pageTOC page'
       pagecats   = pageCategories page'
+      metadata   = filter
+                       (\(k, _) -> not (k `elem`
+                           ["title", "format", "toc", "categories"]))
+                       (pageMeta page')
       metadata'  = (if pagename /= pagetitle
-                       then "!title: " ++ pagetitle ++ "\n"
+                       then "title: " ++ pagetitle ++ "\n"
                        else "") ++
                    (if pageformat /= defaultPageType conf ||
                           pagelhs /= defaultLHS conf
-                       then "!format: " ++
+                       then "format: " ++
                             map toLower (show pageformat) ++
                             if pagelhs then "+lhs\n" else "\n"
                        else "") ++
                    (if pagetoc /= tableOfContents conf
-                       then "!toc: " ++
+                       then "toc: " ++
                             (if pagetoc then "yes" else "no") ++ "\n"
                        else "") ++
                    (if not (null pagecats)
-                       then "!categories: " ++ unwords pagecats ++ "\n"
-                       else "")
-  in  metadata' ++ (if null metadata' then "" else "\n") ++ pageText page'
+                       then "categories: " ++ intercalate ", " pagecats ++ "\n"
+                       else "") ++
+                   (unlines (map (\(k, v) -> k ++ ": " ++ v) metadata))
+  in (if null metadata' then "" else "---\n" ++ metadata' ++ "...\n\n")
+        ++ pageText page'
 
 -- | Read categories from metadata strictly.
 readCategories :: FilePath -> IO [String]
diff --git a/Network/Gitit/Types.hs b/Network/Gitit/Types.hs
--- a/Network/Gitit/Types.hs
+++ b/Network/Gitit/Types.hs
@@ -38,7 +38,7 @@
 import Text.HTML.TagSoup.Entity (lookupEntity)
 import Data.Char (isSpace)
 
-data PageType = Markdown | RST | LaTeX | HTML | Textile
+data PageType = Markdown | RST | LaTeX | HTML | Textile | Org | DocBook
                 deriving (Read, Show, Eq)
 
 data FileStoreType = Git | Darcs | Mercurial deriving Show
@@ -147,7 +147,9 @@
   -- | Directory to search for pandoc customizations
   pandocUserData       :: Maybe FilePath,
   -- | Filter HTML through xss-sanitize
-  xssSanitize          :: Bool
+  xssSanitize          :: Bool,
+  -- | The default number of days in the past to look for \"recent\" activity
+  recentActivityDays   :: Int
   }
 
 -- | Data for rendering a wiki page.
@@ -290,6 +292,7 @@
                      , pSessionKey   :: Maybe SessionKey
                      , pRecaptcha    :: Recaptcha
                      , pResetCode    :: String
+                     , pRedirect     :: Maybe Bool
                      }  deriving Show
 
 instance FromReqURI [String] where
@@ -341,6 +344,10 @@
          rc <- look' "recaptcha_challenge_field" `mplus` return ""
          rr <- look' "recaptcha_response_field" `mplus` return ""
          rk <- look' "reset_code" `mplus` return ""
+         rd <- (look' "redirect" >>= \r -> return (case r of
+             "yes" -> Just True
+             "no" -> Just False
+             _ -> Nothing)) `mplus` return Nothing
          return   Params { pUsername     = un
                          , pPassword     = pw
                          , pPassword2    = p2
@@ -374,6 +381,7 @@
                               recaptchaChallengeField = rc,
                               recaptchaResponseField = rr }
                          , pResetCode    = rk
+                         , pRedirect     = rd
                          }
 
 data Command = Command (Maybe String) deriving Show
@@ -400,7 +408,7 @@
 fromEntities :: String -> String
 fromEntities ('&':xs) =
   case lookupEntity ent of
-        Just c  -> c : fromEntities rest
+        Just c  -> c ++ fromEntities rest
         Nothing -> '&' : fromEntities xs
     where (ent, rest) = case break (\c -> isSpace c || c == ';') xs of
                              (zs,';':ys) -> (zs,ys)
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -6,11 +6,11 @@
 files are stored in a [git][], [darcs][], or [mercurial][] repository
 and may be modified either by using the VCS's command-line tools or
 through the wiki's web interface. By default, pandoc's extended version
-of markdown is used as a markup language, but reStructuredText, LaTeX,
-or HTML can also be used. Pages can be exported in a number of different
-formats, including LaTeX, RTF, OpenOffice ODT, and MediaWiki markup.
-Gitit can be configured to display TeX math (using [texmath][]) and
-highlighted source code (using [highlighting-kate][]).
+of markdown is used as a markup language, but reStructuredText, LaTeX, HTML,
+DocBook, or Emacs Org-mode markup can also be used. Pages can be exported in a
+number of different formats, including LaTeX, RTF, OpenOffice ODT, and
+MediaWiki markup.  Gitit can be configured to display TeX math (using
+[texmath][]) and highlighted source code (using [highlighting-kate][]).
 
 Other features include
 
@@ -298,9 +298,10 @@
 
 For more radical changes, you can override any of the default
 templates in `$CABALDIR/share/gitit-x.y.z/data/templates` by copying
-the file into `templates` and modifying it. The `page.st` template is
-the master template; it includes the others. Interpolated variables are
-surrounded by `$`s, so `literal $` must be backslash-escaped.
+the file into `templates`, modifying it, and restarting gitit. The 
+`page.st` template is the master template; it includes the others. 
+Interpolated variables are surrounded by `$`s, so `literal $` must 
+be backslash-escaped.
 
 Adding support for math
 -----------------------
@@ -348,9 +349,9 @@
 =======
 
 Plugins are small Haskell programs that transform a wiki page after it
-has been converted from Markdown or RST. See the example plugins in the
-`plugins` directory. To enable a plugin, include the path to the plugin
-(or its module name) in the `plugins` field of the configuration file.
+has been converted from Markdown or another source format. See the example
+plugins in the `plugins` directory. To enable a plugin, include the path to the
+plugin (or its module name) in the `plugins` field of the configuration file.
 (If the plugin name starts with `Network.Gitit.Plugin.`, gitit will assume that
 the plugin is an installed module and will not look for a source file.)
 
@@ -544,6 +545,7 @@
       SetOutputFilter  proxy-html
       ProxyPassReverse /
       ProxyHTMLURLMap  /   /wiki/
+      ProxyHTMLDocType "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>" XHTML
       RequestHeader unset Accept-Encoding
     </Location>
 
diff --git a/data/default.conf b/data/default.conf
--- a/data/default.conf
+++ b/data/default.conf
@@ -54,7 +54,7 @@
 default-page-type: Markdown
 # specifies the type of markup used to interpret pages in the wiki.
 # Possible values are Markdown, RST, LaTeX, HTML, Markdown+LHS, RST+LHS,
-# and LaTeX+LHS. (The +LHS variants treat the input as
+# LaTeX+LHS, DocBook, Org. (The +LHS variants treat the input as
 # literate Haskell. See pandoc's documentation for more details.) If
 # Markdown is selected, pandoc's syntax extensions (for footnotes,
 # delimited code blocks, etc.) will be enabled. Note that pandoc's
@@ -238,8 +238,8 @@
 
 base-url:
 # the base URL of the wiki, to be used in constructing feed IDs
-# and RPX token_urls.  Set this if use-feed is 'yes' or
-# authentication-method is 'rpx'.
+# and RPX token_urls.
+# Set this if use-feed is 'yes' or authentication-method is 'rpx'.
 
 absolute-urls: no
 # make wikilinks absolute with respect to the base-url.
@@ -270,3 +270,8 @@
 xss-sanitize: yes
 # if yes, all HTML (including that produced by pandoc) is filtered
 # through xss-sanitize.  Set to no only if you trust all of your users.
+
+recent-activity-days: 30
+# if the activity page receives no 'since' parameter specifiying the time
+# thereafter which to show the changes, it will by default show "recent"
+# changes. This allows you to specify how recent "recent" means, in days.
diff --git a/data/markup.DocBook b/data/markup.DocBook
new file mode 100644
--- /dev/null
+++ b/data/markup.DocBook
@@ -0,0 +1,347 @@
+<sect1 id="markdown">
+  <title>Markdown</title>
+  <para>
+    This wiki's pages are written in
+    <ulink url="http://johnmacfarlane.net/pandoc">pandoc</ulink>'s
+    extended form of
+    <ulink url="http://daringfireball.net/projects/markdown">markdown</ulink>.
+    If you're not familiar with markdown, you should start by looking at
+    the
+    <ulink url="http://daringfireball.net/projects/markdown/basics">markdown
+    &quot;basics&quot; page</ulink> and the
+    <ulink url="http://daringfireball.net/projects/markdown/syntax">markdown
+    syntax description</ulink>. Consult the
+    <ulink url="http://johnmacfarlane.net/pandoc/README.html">pandoc
+    User's Guide</ulink> for information about pandoc's syntax for
+    footnotes, tables, description lists, and other elements not present
+    in standard markdown.
+  </para>
+  <para>
+    Markdown is pretty intuitive, since it is based on email
+    conventions. Here are some examples to get you started:
+  </para>
+  <table>
+  <tr>
+  <td>
+  <literal>*emphasized text*</literal>
+  </td>
+  <td>
+  <emphasis>emphasized text</emphasis>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>**strong emphasis**</literal>
+  </td>
+  <td>
+  <emphasis role="strong">strong emphasis</emphasis>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>`literal text`</literal>
+  </td>
+  <td>
+  <literal>literal text</literal>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>\*escaped special characters\*</literal>
+  </td>
+  <td>
+  *escaped special characters*
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>[external link](http://google.com)</literal>
+  </td>
+  <td>
+  <ulink url="http://google.com">external link</ulink>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>![folder](/img/icons/folder.png)</literal>
+  </td>
+  <td>
+  <inlinemediaobject>
+    <imageobject>
+      <imagedata fileref="/img/icons/folder.png" />
+    </imageobject>
+  </inlinemediaobject>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  Wikilink: <literal>[Front Page]()</literal>
+  </td>
+  <td>
+  Wikilink: <ulink url="">Front Page</ulink>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>H~2~O</literal>
+  </td>
+  <td>
+  H<subscript>2</subscript>O
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>10^100^</literal>
+  </td>
+  <td>
+  10<superscript>100</superscript>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>~~strikeout~~</literal>
+  </td>
+  <td>
+  <emphasis role="strikethrough">strikeout</emphasis>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>$x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$</literal>
+  </td>
+  <td>
+  $x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$<footnote>
+    <para>
+      If this looks like code, it's because jsMath is not installed on
+      your system. Contact your administrator to request it.
+    </para>
+  </footnote>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <literal>A simple footnote.^[Or is it so simple?]</literal>
+  </td>
+  <td>
+  A simple footnote.<footnote>
+    <para>
+      Or is it so simple?
+    </para>
+  </footnote>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <pre>
+  > an indented paragraph,
+  > usually used for quotations
+  </pre>
+  </td>
+  <td>
+  <blockquote>
+    <para>
+      an indented paragraph, usually used for quotations
+    </para>
+  </blockquote>
+  </td>
+  <tr>
+  <td>
+  <pre>
+      #!/bin/sh -e
+      # code, indented four spaces
+      echo "Hello world"
+  </pre>
+  </td>
+  <td>
+  <programlisting>
+#!/bin/sh -e
+# code, indented four spaces
+echo &quot;Hello world&quot;
+</programlisting>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <pre>
+  * a bulleted list
+  * second item
+      - sublist
+      - and more
+  * back to main list
+      1. this item has an ordered
+      2. sublist
+          a) you can also use letters
+          b) another item
+  </pre>
+  </td>
+  <td>
+  <itemizedlist spacing="compact">
+    <listitem>
+      <para>
+        a bulleted list
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+        second item
+      </para>
+      <itemizedlist spacing="compact">
+        <listitem>
+          <para>
+            sublist
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            and more
+          </para>
+        </listitem>
+      </itemizedlist>
+    </listitem>
+    <listitem>
+      <para>
+        back to main list
+      </para>
+      <orderedlist numeration="arabic" spacing="compact">
+        <listitem>
+          <para>
+            this item has an ordered
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            sublist
+          </para>
+          <orderedlist numeration="loweralpha" spacing="compact">
+            <listitem>
+              <para>
+                you can also use letters
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                another item
+              </para>
+            </listitem>
+          </orderedlist>
+        </listitem>
+      </orderedlist>
+    </listitem>
+  </itemizedlist>
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <pre>
+  Fruit        Quantity
+  --------  -----------
+  apples         30,200
+  oranges         1,998
+  pears              42
+
+  Table:  Our fruit inventory
+  </pre>
+  </td>
+  <td>
+  <table>
+    <title>
+      Our fruit inventory
+    </title>
+    <tgroup cols="2">
+      <colspec align="left" />
+      <colspec align="right" />
+      <thead>
+        <row>
+          <entry>
+            Fruit
+          </entry>
+          <entry>
+            Quantity
+          </entry>
+        </row>
+      </thead>
+      <tbody>
+        <row>
+          <entry>
+            apples
+          </entry>
+          <entry>
+            30,200
+          </entry>
+        </row>
+        <row>
+          <entry>
+            oranges
+          </entry>
+          <entry>
+            1,998
+          </entry>
+        </row>
+        <row>
+          <entry>
+            pears
+          </entry>
+          <entry>
+            42
+          </entry>
+        </row>
+      </tbody>
+    </tgroup>
+  </table>
+  </td>
+  </tr>
+  </table>
+  <para>
+    For headings, prefix a line with one or more <literal>#</literal>
+    signs: one for a major heading, two for a subheading, three for a
+    subsubheading. Be sure to leave space before and after the heading.
+  </para>
+  <programlisting>
+# Markdown
+
+Text...
+
+## Some examples...
+
+Text...
+</programlisting>
+  <sect2 id="wiki-links">
+    <title>Wiki links</title>
+    <para>
+      Links to other wiki pages are formed this way:
+      <literal>[Page Name]()</literal>. (Gitit converts markdown links
+      with empty targets into wikilinks.)
+    </para>
+    <para>
+      To link to a wiki page using something else as the link text:
+      <literal>[something else](Page Name)</literal>.
+    </para>
+    <para>
+      Note that page names may contain spaces and some special
+      characters. They need not be CamelCase. CamelCase words are
+      <emphasis>not</emphasis> automatically converted to wiki links.
+    </para>
+    <para>
+      Wiki pages may be organized into directories. So, if you have
+      several pages on wine, you may wish to organize them like so:
+    </para>
+    <programlisting>
+Wine/Pinot Noir
+Wine/Burgundy
+Wine/Cabernet Sauvignon
+</programlisting>
+    <para>
+      Note that a wiki link <literal>[Burgundy]()</literal> that occurs
+      inside the <literal>Wine</literal> directory will link to
+      <literal>Wine/Burgundy</literal>, and not to
+      <literal>Burgundy</literal>. To link to a top-level page called
+      <literal>Burgundy</literal>, you'd have to use
+      <literal>[Burgundy](/Burgundy)</literal>.
+    </para>
+    <para>
+      To link to a directory listing for a subdirectory, use a trailing
+      slash: <literal>[Wine/]()</literal> will link to a listing of the
+      <literal>Wine</literal> subdirectory.
+    </para>
+  </sect2>
+</sect1>
diff --git a/data/markup.Org b/data/markup.Org
new file mode 100644
--- /dev/null
+++ b/data/markup.Org
@@ -0,0 +1,356 @@
+* Markdown
+
+This wiki's pages are written in
+[[http://johnmacfarlane.net/pandoc][pandoc]]'s extended form of
+[[http://daringfireball.net/projects/markdown][markdown]]. If you're not
+familiar with markdown, you should start by looking at the
+[[http://daringfireball.net/projects/markdown/basics][markdown "basics"
+page]] and the
+[[http://daringfireball.net/projects/markdown/syntax][markdown syntax
+description]]. Consult the
+[[http://johnmacfarlane.net/pandoc/README.html][pandoc User's Guide]]
+for information about pandoc's syntax for footnotes, tables, description
+lists, and other elements not present in standard markdown.
+
+Markdown is pretty intuitive, since it is based on email conventions.
+Here are some examples to get you started:
+
+#+BEGIN_HTML
+  <table>
+  <tr>
+  <td>
+#+END_HTML
+
+=*emphasized text*=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+/emphasized text/
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=**strong emphasis**=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+*strong emphasis*
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=`literal text`=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+=literal text=
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=\*escaped special characters\*=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+*escaped special characters*
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=[external link](http://google.com)=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+[[http://google.com][external link]]
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=![folder](/img/icons/folder.png)=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+[[/img/icons/folder.png]]
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+Wikilink: =[Front Page]()=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+Wikilink: [[][Front Page]]
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=H~2~O=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+H_{2}O
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=10^100^=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+10^{100}
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=~~strikeout~~=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
++strikeout+
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=$x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+$x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$ [1]
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+#+END_HTML
+
+=A simple footnote.^[Or is it so simple?]=
+
+#+BEGIN_HTML
+  </td>
+  <td>
+#+END_HTML
+
+A simple footnote. [2]
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <pre>
+  > an indented paragraph,
+  > usually used for quotations
+  </pre>
+  </td>
+  <td>
+#+END_HTML
+
+#+BEGIN_QUOTE
+  an indented paragraph, usually used for quotations
+#+END_QUOTE
+
+#+BEGIN_HTML
+  </td>
+  <tr>
+  <td>
+  <pre>
+      #!/bin/sh -e
+      # code, indented four spaces
+      echo "Hello world"
+  </pre>
+  </td>
+  <td>
+#+END_HTML
+
+#+BEGIN_EXAMPLE
+    #!/bin/sh -e
+    # code, indented four spaces
+    echo "Hello world"
+#+END_EXAMPLE
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <pre>
+  * a bulleted list
+  * second item
+      - sublist
+      - and more
+  * back to main list
+      1. this item has an ordered
+      2. sublist
+          a) you can also use letters
+          b) another item
+  </pre>
+  </td>
+  <td>
+#+END_HTML
+
+-  a bulleted list
+-  second item
+
+   -  sublist
+   -  and more
+
+-  back to main list
+
+   1. this item has an ordered
+   2. sublist
+
+      1) you can also use letters
+      2) another item
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  <tr>
+  <td>
+  <pre>
+  Fruit        Quantity
+  --------  -----------
+  apples         30,200
+  oranges         1,998
+  pears              42
+
+  Table:  Our fruit inventory
+  </pre>
+  </td>
+  <td>
+#+END_HTML
+
+| Fruit     | Quantity   |
+|-----------+------------|
+| apples    | 30,200     |
+| oranges   | 1,998      |
+| pears     | 42         |
+#+CAPTION: Our fruit inventory
+
+#+BEGIN_HTML
+  </td>
+  </tr>
+  </table>
+#+END_HTML
+
+For headings, prefix a line with one or more =#= signs: one for a major
+heading, two for a subheading, three for a subsubheading. Be sure to
+leave space before and after the heading.
+
+#+BEGIN_EXAMPLE
+    # Markdown
+
+    Text...
+
+    ## Some examples...
+
+    Text...
+#+END_EXAMPLE
+
+** Wiki links
+
+Links to other wiki pages are formed this way: =[Page Name]()=. (Gitit
+converts markdown links with empty targets into wikilinks.)
+
+To link to a wiki page using something else as the link text:
+=[something else](Page Name)=.
+
+Note that page names may contain spaces and some special characters.
+They need not be CamelCase. CamelCase words are /not/ automatically
+converted to wiki links.
+
+Wiki pages may be organized into directories. So, if you have several
+pages on wine, you may wish to organize them like so:
+
+#+BEGIN_EXAMPLE
+    Wine/Pinot Noir
+    Wine/Burgundy
+    Wine/Cabernet Sauvignon
+#+END_EXAMPLE
+
+Note that a wiki link =[Burgundy]()= that occurs inside the =Wine=
+directory will link to =Wine/Burgundy=, and not to =Burgundy=. To link
+to a top-level page called =Burgundy=, you'd have to use
+=[Burgundy](/Burgundy)=.
+
+To link to a directory listing for a subdirectory, use a trailing slash:
+=[Wine/]()= will link to a listing of the =Wine= subdirectory.
+
+[1] If this looks like code, it's because jsMath is not installed on
+    your system. Contact your administrator to request it.
+
+[2] Or is it so simple?
diff --git a/data/markup.Textile b/data/markup.Textile
new file mode 100644
--- /dev/null
+++ b/data/markup.Textile
@@ -0,0 +1,254 @@
+h1(#markdown). Markdown
+
+This wiki's pages are written in "pandoc":http://johnmacfarlane.net/pandoc's extended form of "markdown":http://daringfireball.net/projects/markdown. If you're not familiar with markdown, you should start by looking at the "markdown &quot;basics&quot; page":http://daringfireball.net/projects/markdown/basics and the "markdown syntax description":http://daringfireball.net/projects/markdown/syntax. Consult the "pandoc User's Guide":http://johnmacfarlane.net/pandoc/README.html for information about pandoc's syntax for footnotes, tables, description lists, and other elements not present in standard markdown.
+
+Markdown is pretty intuitive, since it is based on email conventions. Here are some examples to get you started:
+
+<table>
+<tr>
+<td>
+@*emphasized text*@
+</td>
+<td>
+_emphasized text_
+</td>
+</tr>
+<tr>
+<td>
+@**strong emphasis**@
+</td>
+<td>
+*strong emphasis*
+</td>
+</tr>
+<tr>
+<td>
+@`literal text`@
+</td>
+<td>
+@literal text@
+</td>
+</tr>
+<tr>
+<td>
+@\*escaped special characters\*@
+</td>
+<td>
+&#42;escaped special characters&#42;
+</td>
+</tr>
+<tr>
+<td>
+@[external link](http://google.com)@
+</td>
+<td>
+"external link":http://google.com
+</td>
+</tr>
+<tr>
+<td>
+@![folder](/img/icons/folder.png)@
+</td>
+<td>
+!/img/icons/folder.png(folder)!
+</td>
+</tr>
+<tr>
+<td>
+Wikilink: @[Front Page]()@
+</td>
+<td>
+Wikilink: "Front Page":
+</td>
+</tr>
+<tr>
+<td>
+@H~2~O@
+</td>
+<td>
+H[~2~]O
+</td>
+</tr>
+<tr>
+<td>
+@10^100^@
+</td>
+<td>
+10[^100^]
+</td>
+</tr>
+<tr>
+<td>
+@~~strikeout~~@
+</td>
+<td>
+-strikeout-
+</td>
+</tr>
+<tr>
+<td>
+@$x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$@
+</td>
+<td>
+<span class="math">x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}</math>[1]
+</td>
+</tr>
+<tr>
+<td>
+@A simple footnote.^[Or is it so simple?]@
+</td>
+<td>
+A simple footnote.[2]
+</td>
+</tr>
+<tr>
+<td>
+<pre>
+> an indented paragraph,
+> usually used for quotations
+</pre>
+</td>
+<td>
+
+bq. an indented paragraph, usually used for quotations
+
+
+
+</td>
+<tr>
+<td>
+<pre>
+    #!/bin/sh -e
+    # code, indented four spaces
+    echo "Hello world"
+</pre>
+</td>
+<td>
+
+bc. #!/bin/sh -e
+# code, indented four spaces
+echo "Hello world"
+
+
+</td>
+</tr>
+<tr>
+<td>
+<pre>
+* a bulleted list
+* second item
+    - sublist
+    - and more
+* back to main list
+    1. this item has an ordered
+    2. sublist
+        a) you can also use letters
+        b) another item
+</pre>
+</td>
+<td>
+
+<ul>
+<li>a bulleted list</li>
+<li>second item
+<ul>
+<li>sublist</li>
+<li>and more</li>
+</ul>
+</li>
+<li>back to main list
+<ol style="list-style-type: decimal;">
+<li>this item has an ordered</li>
+<li>sublist
+<ol style="list-style-type: lower-alpha;">
+<li>you can also use letters</li>
+<li>another item</li>
+</ol>
+</li>
+</ol>
+</li>
+</ul>
+
+</td>
+</tr>
+<tr>
+<td>
+<pre>
+Fruit        Quantity
+--------  -----------
+apples         30,200
+oranges         1,998
+pears              42
+
+Table:  Our fruit inventory
+</pre>
+</td>
+<td>
+
+<table>
+<caption>Our fruit inventory</caption>
+<thead>
+<tr class="header">
+<th align="left">Fruit</th>
+<th align="right">Quantity</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="left">apples</td>
+<td align="right">30,200</td>
+</tr>
+<tr class="even">
+<td align="left">oranges</td>
+<td align="right">1,998</td>
+</tr>
+<tr class="odd">
+<td align="left">pears</td>
+<td align="right">42</td>
+</tr>
+</tbody>
+</table>
+
+</td>
+</tr>
+</table>
+
+For headings, prefix a line with one or more @#@ signs: one for a major heading, two for a subheading, three for a subsubheading. Be sure to leave space before and after the heading.
+
+<pre>
+# Markdown
+
+Text...
+
+## Some examples...
+
+Text...
+</pre>
+
+h2(#wiki-links). Wiki links
+
+Links to other wiki pages are formed this way: @[Page Name]()@. (Gitit converts markdown links with empty targets into wikilinks.)
+
+To link to a wiki page using something else as the link text: @[something else](Page Name)@.
+
+Note that page names may contain spaces and some special characters. They need not be CamelCase. CamelCase words are _not_ automatically converted to wiki links.
+
+Wiki pages may be organized into directories. So, if you have several pages on wine, you may wish to organize them like so:
+
+bc. Wine/Pinot Noir
+Wine/Burgundy
+Wine/Cabernet Sauvignon
+
+
+Note that a wiki link @[Burgundy]()@ that occurs inside the @Wine@ directory will link to @Wine/Burgundy@, and not to @Burgundy@. To link to a top-level page called @Burgundy@, you'd have to use @[Burgundy](/Burgundy)@.
+
+To link to a directory listing for a subdirectory, use a trailing slash: @[Wine/]()@ will link to a listing of the @Wine@ subdirectory.
+
+
+fn1. If this looks like code, it's because jsMath is not installed on your system. Contact your administrator to request it.
+
+
+fn2. Or is it so simple?
+
+
+
diff --git a/data/static/css/screen.css b/data/static/css/screen.css
--- a/data/static/css/screen.css
+++ b/data/static/css/screen.css
@@ -16,7 +16,7 @@
 table, tr, td, th { border: none; }
 hr { height: 1px; color: #aaa; background-color: #aaa; border: 0; margin: .2em 0 .2em 0; }
 
-h1, h2, h3, h4, h5, h6 { font-weight: normal; border-bottom: 1px solid black; }
+h1, h2, h3, h4, h5, h6 { font-weight: normal; border-bottom: 1px solid #aaa; }
 
 h1.pageTitle { font-size: 197%; margin: 0.2em 0 .5em; }
 
@@ -106,7 +106,8 @@
 .search_result { margin-bottom: 15px; }
 .search_result .match { margin-bottom: 15px; }
 
-code { font-size: 93%; }
+pre>code { display: block; padding: 0.7em 1em; }
+code { font-size: 93%; background-color: #f8f8f8; border: 1px solid #ddd; overflow: auto; border-radius: 0.2em; }
 pre.matches { margin: 0; padding: 0; }
 #pattern { background-color: yellow; font-weight: bold; }
 pre.matches span.highlighted { background-color: yellow; }
@@ -130,6 +131,7 @@
 .index li.page { background-image: url(../img/icons/page.png); }
 .index li.folder { background-image: url(../img/icons/folder.png); }
 .index a { color: #000000; cursor: pointer; text-decoration: none; }
+.index a + a { margin-left: 0.5em; }
 .index a:hover { text-decoration: underline; }
 
 a.updir { font-weight: bold; }
diff --git a/data/static/js/search.js b/data/static/js/search.js
--- a/data/static/js/search.js
+++ b/data/static/js/search.js
@@ -2,7 +2,7 @@
 {
     // patt is a space separated list of strings - we want to highlight
     // an occurrence of any of these strings as a separate word.
-    var regex = new RegExp('\\b(' + patt.replace(/ /, '|') + ')\\b', 'g');
+    var regex = new RegExp('\\b(' + patt.replace(/ /g, '|') + ')\\b', 'gi');
 
     return this.each(function ()
     {
diff --git a/data/templates/sitenav.st b/data/templates/sitenav.st
--- a/data/templates/sitenav.st
+++ b/data/templates/sitenav.st
@@ -15,7 +15,7 @@
       $endif$
       <li><a href="$base$/Help">Help</a></li>
     </ul>
-    <form action="$base$/_search" method="post" id="searchform">
+    <form action="$base$/_search" method="get" id="searchform">
      <input type="text" name="patterns" id="patterns"/>
      <input type="submit" name="search" id="search" value="Search"/>
     </form>
diff --git a/gitit.cabal b/gitit.cabal
--- a/gitit.cabal
+++ b/gitit.cabal
@@ -1,5 +1,5 @@
 name:                gitit
-version:             0.10.3.1
+version:             0.10.4
 Cabal-version:       >= 1.6
 build-type:          Simple
 synopsis:            Wiki using happstack, git or darcs, and pandoc.
@@ -68,6 +68,7 @@
                      data/s5/default/slides.min.js,
                      data/post-update, data/FrontPage.page, data/Help.page,
                      data/markup.Markdown, data/markup.RST,
+                     data/markup.Textile, data/markup.Org, data/markup.DocBook,
                      data/markup.HTML, data/markup.LaTeX,
                      data/default.conf,
                      data/templates/page.st, data/templates/content.st,
@@ -117,8 +118,8 @@
     exposed-modules: Network.Gitit.Interface
     build-depends:   ghc, ghc-paths
     cpp-options:     -D_PLUGINS
-  build-depends:     base >= 3, pandoc >= 1.10.0.5 && < 1.12,
-                     pandoc-types >= 1.10 && < 1.11, filepath, safe
+  build-depends:     base >= 3, pandoc >= 1.12.4 && < 1.13,
+                     pandoc-types >= 1.12.3 && < 1.13, filepath, safe
   extensions:        CPP
   if impl(ghc >= 6.12)
     ghc-options:     -Wall -fno-warn-unused-do-bind
@@ -134,19 +135,18 @@
                      pretty,
                      xhtml,
                      containers,
-                     pandoc >= 1.10.0.5 && < 1.12,
-                     pandoc-types >= 1.10 && < 1.11,
+                     pandoc >= 1.12.4 && < 1.13,
+                     pandoc-types >= 1.12.3 && < 1.13,
                      process,
                      filepath,
                      directory,
                      mtl,
-                     cgi,
                      old-time,
                      highlighting-kate >= 0.5.0.1 && < 0.6,
                      bytestring,
                      text,
                      random,
-                     network >= 2.1.0.0 && < 2.5,
+                     network >= 2.3 && < 2.6,
                      utf8-string >= 0.3 && < 0.4,
                      SHA > 1 && < 1.7,
                      HTTP >= 4000.0 && < 4000.3,
@@ -157,22 +157,20 @@
                      filestore >= 0.6 && < 0.7,
                      zlib >= 0.5 && < 0.6,
                      url >= 2.1 && < 2.2,
-                     happstack-server >= 7.0 && < 7.2,
+                     happstack-server >= 7.0 && < 7.4,
                      base64-bytestring >= 0.1 && < 1.1,
                      xml >= 1.3.5,
                      hslogger >= 1 && < 1.3,
                      ConfigFile >= 1 && < 1.2,
                      feed >= 0.3.6 && < 0.4,
                      xss-sanitize >= 0.3 && < 0.4,
-                     tagsoup >= 0.12 && < 0.13,
-                     blaze-html >= 0.4 && < 0.7,
-                     json >= 0.4 && < 0.8
+                     tagsoup >= 0.13 && < 0.14,
+                     blaze-html >= 0.4 && < 0.8,
+                     json >= 0.4 && < 0.8,
+                     uri >= 0.1 && < 0.2,
+                     split
   if impl(ghc >= 6.10)
     build-depends:   base >= 4, syb
-  if impl(ghc >= 7.0.3)
-    -- without this, 'cabal install' tries to install an older
-    -- version of network; I'm not sure why:
-    build-depends:   network >= 2.3 && < 2.5
   if flag(plugins)
     build-depends:   ghc, ghc-paths
     cpp-options:     -D_PLUGINS
diff --git a/plugins/Subst.hs b/plugins/Subst.hs
--- a/plugins/Subst.hs
+++ b/plugins/Subst.hs
@@ -8,7 +8,7 @@
 
 import Control.Monad.CatchIO (try)
 import Data.FileStore (FileStoreError, retrieve)
-import Text.Pandoc (defaultParserState, readMarkdown)
+import Text.Pandoc (def, readMarkdown)
 import Network.Gitit.ContentTransformer (inlinesToString)
 import Network.Gitit.Interface
 import Network.Gitit.Framework (filestoreFromConfig)
@@ -27,7 +27,7 @@
                             alt = "'" ++ target ++ "' doesn't exist. Click here to create it."
                             lnk = Para [Link [txt] (target,alt)]
                         in  (lnk :) `fmap` substituteIntoBlock xs
-          Right a    -> let (Pandoc _ content) = readMarkdown defaultParserState a
+          Right a    -> let (Pandoc _ content) = readMarkdown def a
                         in  (content ++) `fmap` substituteIntoBlock xs
 substituteIntoBlock (x:xs) = (x:) `fmap` substituteIntoBlock xs
 substituteIntoBlock [] = return []
