diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,55 @@
+Version 0.7 released 20 Dec 2009
+
+* Updated cabal file to allow happstack 0.4.
+
+* Added support for the new mercurial filestore backend.
+  (Depending on filestore >= 0.3.4.)
+
+* Depend on xml >= 1.3.5.  This fixes a bug in the display of
+  mathml.  Previously the self-closed tags in matrices with empty
+  cells confused browsers and caused them to construct the
+  DOM incorrectly. The problem is fixed by using xml's new
+  ppcElement function to render the MathML without self-closed tags.
+
+* Depend on pandoc >= 1.3.
+
+* Properly handle UTF-8 in config files.
+
+* Moved option parsing code from Config module to main program.
+  The Config module now exports getConfigFromFile instead of
+  getConfigFromOpts. This should be more useful for those using gitit as
+  a library.
+
+* Use wikiTitle config field in default HTML title.
+
+* Improved search results:
+  + Highlight search terms in search results.
+    Partially resolves Issue #76.
+  + Made search results message uniform when no results.
+  + Search: don't match page name against empty patterns.
+  + Allow search matches on subdirectory part of page name.
+  + Search:  catch error status from filestore search.
+    Filestore <= 0.3.3 does not properly handle the error status
+    returned by later versions of 'git grep' when no match is found.
+    The problem has been fixed in darcs filestore.
+
+* CSS tweaks:
+  + Removed base-min.css, folded necessary styles into screen.css.
+  + Removed 'text-align: left' for th from CSS reset.
+
+* Feed improvements:
+  + Modified feed handling so that feeds validate.
+  + Perform proper escaping in Feed.hs (thanks to gwern).
+  + Don't reveal author email in feeds.
+  + Sitewide feed is /_feed/ (with trailing slash).
+  + Add "http://" to base-url config option if needed.
+
+* Use + for spaces in URLs linking to wiki pages and folders.
+
+* Updated plugins:
+  + Updated Interwiki plugin (gwern).
+  + Modified WebArchiver plugin to make Alexa requests (gwern).
+
 Version 0.6.6 released 06 Nov 2009
 
 * Require filestore >= 0.3.3, which closes a security
diff --git a/Network/Gitit/Config.hs b/Network/Gitit/Config.hs
--- a/Network/Gitit/Config.hs
+++ b/Network/Gitit/Config.hs
@@ -20,9 +20,9 @@
 {- | Functions for parsing command line options and reading the config file.
 -}
 
-module Network.Gitit.Config ( getConfigFromOpts
-                            , readMimeTypesFile
-                            , getDefaultConfig )
+module Network.Gitit.Config ( getConfigFromFile
+                            , getDefaultConfig
+                            , readMimeTypesFile )
 where
 import Safe
 import Network.Gitit.Types
@@ -32,87 +32,36 @@
 import Network.Gitit.Util (parsePageType)
 import System.Log.Logger (logM, Priority(..))
 import qualified Data.Map as M
-import System.Environment
-import System.Exit
-import System.IO (stdout, stderr)
-import System.Console.GetOpt
-import Data.ConfigFile
+import Data.ConfigFile hiding (readfile)
 import Control.Monad.Error
 import System.Log.Logger ()
 import Data.List (intercalate)
 import Data.Char (toLower, toUpper, isDigit)
-import Data.Version (showVersion)
-import Paths_gitit (getDataFileName, version)
+import Paths_gitit (getDataFileName)
 import Prelude hiding (readFile)
 import System.IO.UTF8
 import System.FilePath ((</>))
 import Control.Monad (liftM)
 import Text.Pandoc
 
-data Opt
-    = Help
-    | ConfigFile FilePath
-    | Port Int
-    | Debug
-    | Version
-    | PrintDefaultConfig
-    deriving (Eq)
-
-flags :: [OptDescr Opt]
-flags =
-   [ Option ['h'] ["help"] (NoArg Help)
-        "Print this help message"
-   , Option ['v'] ["version"] (NoArg Version)
-        "Print version information"
-   , Option ['p'] ["port"] (ReqArg (Port . read) "PORT")
-        "Specify port"
-   , Option [] ["print-default-config"] (NoArg PrintDefaultConfig)
-        "Print default configuration"
-   , Option ['d'] ["debug"] (NoArg Debug)
-        "Print debugging information on each request"
-   , Option ['f'] ["config-file"] (ReqArg ConfigFile "FILE")
-        "Specify configuration file"
-   ]
-
-parseArgs :: [String] -> IO [Opt]
-parseArgs argv = do
-  progname <- getProgName
-  case getOpt Permute flags argv of
-    (opts,_,[])  -> return opts
-    (_,_,errs)   -> hPutStrLn stderr (concat errs ++ usageInfo (usageHeader progname) flags) >>
-                       exitWith (ExitFailure 1)
-
-usageHeader :: String -> String
-usageHeader progname = "Usage:  " ++ progname ++ " [opts...]"
-
-copyrightMessage :: String
-copyrightMessage = "\nCopyright (C) 2008 John MacFarlane\n" ++
-                   "This is free software; see the source for copying conditions.  There is no\n" ++
-                   "warranty, not even for merchantability or fitness for a particular purpose."
-
-compileInfo :: String
-compileInfo =
-#ifdef _PLUGINS
-  " +plugins"
-#else
-  " -plugins"
-#endif
-
 forceEither :: Show e => Either e a -> a
 forceEither = either (error . show) id
 
-handleFlag :: ConfigParser -> Config -> Opt -> IO Config
-handleFlag cp conf opt = do
-  progname <- getProgName
-  case opt of
-    Help               -> hPutStrLn stderr (usageInfo (usageHeader progname) flags) >> exitWith ExitSuccess
-    Version            -> hPutStrLn stderr (progname ++ " version " ++ showVersion version ++ compileInfo ++ copyrightMessage) >> exitWith ExitSuccess
-    PrintDefaultConfig -> getDataFileName "data/default.conf" >>= readFile >>=
-                          hPutStrLn stdout >> exitWith ExitSuccess
-    Debug              -> return conf{ debugMode = True }
-    Port p             -> return conf{ portNumber = p }
-    ConfigFile fname   -> readfile cp fname >>= extractConfig . forceEither
+-- | Get configuration from config file.
+getConfigFromFile :: FilePath -> IO Config
+getConfigFromFile fname = do
+  cp <- getDefaultConfigParser
+  readfile cp fname >>= extractConfig . forceEither
 
+-- | A version of readfile that treats the file as UTF-8.
+readfile :: MonadError CPError m
+          => ConfigParser
+          -> FilePath
+          -> IO (m ConfigParser)
+readfile cp path' = do
+  contents <- readFile path'
+  return $ readstring cp contents
+
 extractConfig :: ConfigParser -> IO Config
 extractConfig cp = do
   config' <- runErrorT $ do
@@ -162,9 +111,10 @@
       let authMethod = map toLower cfAuthenticationMethod
       let stripTrailingSlash = reverse . dropWhile (=='/') . reverse
       let repotype' = case map toLower cfRepositoryType of
-                        "git"   -> Git
-                        "darcs" -> Darcs
-                        x       -> error $ "Unknown repository type: " ++ x
+                        "git"       -> Git
+                        "darcs"     -> Darcs
+                        "mercurial" -> Mercurial
+                        x           -> error $ "Unknown repository type: " ++ x
 
       return $! Config{
           repositoryPath       = cfRepositoryPath
@@ -265,16 +215,6 @@
 -- | Returns the default gitit configuration.
 getDefaultConfig :: IO Config
 getDefaultConfig = getDefaultConfigParser >>= extractConfig
-
--- | Parses command line options and returns configuration
--- based on the options (-f FILE specifies a configuration
--- file; some settings, such as port number, can be overridden
--- by a command line option).
-getConfigFromOpts :: IO Config
-getConfigFromOpts = do
-  cp' <- getDefaultConfigParser
-  defaultConfig <- extractConfig cp'
-  getArgs >>= parseArgs >>= foldM (handleFlag cp') defaultConfig
 
 -- | Read a file associating mime types with extensions, and return a
 -- map from extensions to types. Each line of the file consists of a
diff --git a/Network/Gitit/ContentTransformer.hs b/Network/Gitit/ContentTransformer.hs
--- a/Network/Gitit/ContentTransformer.hs
+++ b/Network/Gitit/ContentTransformer.hs
@@ -525,8 +525,9 @@
 convertTeXMathToMathML (Math t x) = do
   case texMathToMathML t' x of
        Left _  -> return $ Math t x
-       Right v -> put True >> return (HtmlInline $ ppElement v)
+       Right v -> put True >> return (HtmlInline $ showXml v)
     where t' = if t == DisplayMath then DisplayBlock else DisplayInline
+          showXml = ppcElement (useShortEmptyTags (const False) defaultConfigPP)
 convertTeXMathToMathML x = return x
 
 -- | Derives a URL from a list of Pandoc Inline elements.
diff --git a/Network/Gitit/Feed.hs b/Network/Gitit/Feed.hs
--- a/Network/Gitit/Feed.hs
+++ b/Network/Gitit/Feed.hs
@@ -22,17 +22,20 @@
 
 module Network.Gitit.Feed (FeedConfig(..), filestoreToXmlFeed) where
 
-import Text.Atom.Feed
-import Text.Atom.Feed.Export
-import Text.XML.Light
-import Data.FileStore.Types
-import Data.Maybe
-import Data.DateTime
-import System.FilePath
 import Control.Monad
+import Data.DateTime
 import Data.List (intercalate, sortBy)
+import Data.Maybe
 import Data.Ord (comparing)
+import Network.URI (isAllowedInURI, escapeURIString)
+import System.FilePath
 
+import Data.FileStore.Types
+
+import Text.Atom.Feed
+import Text.Atom.Feed.Export
+import Text.XML.Light
+
 data FeedConfig = FeedConfig {
     fcTitle    :: String
   , fcBaseUrl  :: String
@@ -55,7 +58,7 @@
                      [] -> []
                      (x:_) -> x : init rs   -- so we can get revids for diffs
   now <- liftM formatFeedTime getCurrentTime
-  return $ Feed { feedId = fcBaseUrl cfg ++ "/" ++ path'
+  return $ Feed { feedId = fcBaseUrl cfg ++ "/" ++ escape path'
                 , feedTitle = TextString $ fcTitle cfg
                 , feedUpdated = now
                 , feedAuthors = []
@@ -65,7 +68,7 @@
                                                 , genVersion = Nothing
                                                 , genText = "gitit" }
                 , feedIcon = Nothing
-                , feedLinks = []
+                , feedLinks = [ (nullLink (fcBaseUrl cfg ++ "/_feed/" ++ escape path')) {linkRel = Just (Left "self")} ]
                 , feedLogo = Nothing
                 , feedRights = Nothing
                 , feedSubtitle = Nothing
@@ -92,7 +95,9 @@
   baseEntry{ entrySummary = Just $ TextString rd
            , entryAuthors = [Person { personName = authorName ra
                                     , personURI = Nothing 
-                                    , personEmail = Just $ authorEmail ra
+                                    , personEmail = Nothing
+                                      -- gitit is set up not to reveal registration emails. To change this:
+                                      -- let e = authorEmail ra in if e /= "" then Just e else Nothing
                                     , personOther = [] }]
            , entryLinks = [diffLink]
 
@@ -115,8 +120,8 @@
            -- Enclosure seems to be for conveying media, see
            -- https://secure.wikimedia.org/wikipedia/en/wiki/RSS_enclosure
         }
-    where diffLink = Link{ linkHref = fcBaseUrl cfg ++ "/_diff/" ++ firstpath ++ "?to=" ++ rid ++ fromrev
-                         , linkRel = Nothing
+    where diffLink = Link{ linkHref = fcBaseUrl cfg ++ "/_diff/" ++ escape firstpath ++ "?to=" ++ rid ++ fromrev
+                         , linkRel = Just (Left "alternate")
                          , linkType = Nothing
                          , linkHrefLang = Nothing
                          , linkTitle = Nothing
@@ -137,7 +142,7 @@
                                    Added f    -> (dePage f, "")
                                    Deleted f  -> (dePage f, "&from=" ++ revId prevRevision)
                          else (path',"")
-          baseEntry = nullEntry (fcBaseUrl cfg ++ "/" ++ path' ++ "?revision=" ++ rid)
+          baseEntry = nullEntry (fcBaseUrl cfg ++ "/" ++ escape path' ++ "?revision=" ++ rid)
                         (TextString (intercalate ", " $ map showRev rv)) (formatFeedTime rdt)
           showRev (Modified f) = dePage f
           showRev (Added f)    = "added " ++ dePage f
@@ -145,6 +150,9 @@
           dePage f = if takeExtension f == ".page"
                         then dropExtension f
                         else f
+
+escape :: String -> String
+escape = escapeURIString isAllowedInURI
 
 formatFeedTime :: DateTime -> String
 formatFeedTime = formatDateTime "%Y-%m%--%dT%TZ"  -- Why the double hyphen between %m and %d? It works.
diff --git a/Network/Gitit/Framework.hs b/Network/Gitit/Framework.hs
--- a/Network/Gitit/Framework.hs
+++ b/Network/Gitit/Framework.hs
@@ -275,7 +275,9 @@
 -- the wiki base.
 urlForPage :: String -> String
 urlForPage page = "/" ++
-  encString True (\c -> isAscii c && (c `notElem` "?&")) page
+  encString True (\c -> isAscii c && (c `notElem` "?&")) (map spaceToPlus page)
+    where spaceToPlus ' ' = '+'
+          spaceToPlus c   = c
 -- / and @ are left unescaped so that browsers recognize relative URLs and talk pages correctly
 
 -- | Returns the filestore path of the file containing the page's source.
@@ -350,5 +352,6 @@
 filestoreFromConfig :: Config -> FileStore
 filestoreFromConfig conf =
   case repositoryType conf of
-         Git   -> gitFileStore $ repositoryPath conf
-         Darcs -> darcsFileStore $ repositoryPath conf
+         Git       -> gitFileStore       $ repositoryPath conf
+         Darcs     -> darcsFileStore     $ repositoryPath conf
+         Mercurial -> mercurialFileStore $ repositoryPath conf
diff --git a/Network/Gitit/Handlers.hs b/Network/Gitit/Handlers.hs
--- a/Network/Gitit/Handlers.hs
+++ b/Network/Gitit/Handlers.hs
@@ -266,17 +266,21 @@
   fs <- getFileStore
   matchLines <- if null patterns
                    then return []
-                   else liftIO $ search fs SearchQuery{
-                                            queryPatterns = patterns
-                                          , queryWholeWords = True
-                                          , queryMatchAll = True
-                                          , queryIgnoreCase = True }
+                   else liftIO $ catch (search fs SearchQuery{
+                                                  queryPatterns = patterns
+                                                , queryWholeWords = True
+                                                , queryMatchAll = True
+                                                , queryIgnoreCase = True })
+                                       -- catch error, because newer versions of git
+                                       -- return 1 on no match, and filestore <=0.3.3
+                                       -- doesn't handle this properly:
+                                       (\(_ :: FileStoreError)  -> return [])
   let contentMatches = map matchResourceName matchLines
   allPages <- liftM (filter isPageFile) $ liftIO $ index fs
-  let inPageName pageName' x = x `elem` (words $ map toLower $
-                                          dropExtension pageName')
-  let matchesPatterns pageName' = all (inPageName pageName') $
-                                    map (map toLower) patterns
+  let slashToSpace = map (\c -> if c == '/' then ' ' else c)
+  let inPageName pageName' x = x `elem` (words $ slashToSpace $ dropExtension pageName')
+  let matchesPatterns pageName' = not (null patterns) &&
+       all (inPageName (map toLower pageName')) (map (map toLower) patterns)
   let pageNameMatches = filter matchesPatterns allPages
   let allMatchedFiles = nub $ filter isPageFile contentMatches ++
                               pageNameMatches
@@ -287,13 +291,10 @@
   let relevance (f, ms) = length ms + if f `elem` pageNameMatches
                                          then 100
                                          else 0
-  let preamble = if null matches
-                    then h3 << if null patterns
-                                  then ["Please enter a search term."]
-                                  else ["No matches found for '",
-                                         unwords patterns, "':"]
-                    else h3 << [(show $ length matches),
-                                " matches found for '", unwords patterns, "':"]
+  let preamble = if null patterns 
+                    then h3 << ["Please enter a search term."]
+                    else h3 << [ stringToHtml (show (length matches) ++ " matches found for ")
+                               , thespan ! [identifier "pattern"] << unwords patterns]
   base' <- getWikiBase
   let toMatchListItem (file, contents) = li <<
         [ anchor ! [href $ base' ++ urlForPage (dropExtension file)] << dropExtension file
@@ -663,18 +664,19 @@
 fileListToHtml base' prefix files =
   let fileLink (FSFile f) | isPageFile f =
         li ! [theclass "page"  ] <<
-          anchor ! [href $ base' ++ "/" ++ prefix ++ dropExtension f] << dropExtension f
+          anchor ! [href $ base' ++ urlForPage (prefix ++ dropExtension f)] <<
+            dropExtension f
       fileLink (FSFile f) =
-        li ! [theclass "upload"] << anchor ! [href $ base' ++ "/" ++ prefix ++ f] << f
+        li ! [theclass "upload"] << anchor ! [href $ base' ++ urlForPage (prefix ++ f)] << f
       fileLink (FSDirectory f) =
         li ! [theclass "folder"] <<
-          anchor ! [href $ base' ++ "/" ++ prefix ++ f ++ "/"] << f
+          anchor ! [href $ base' ++ urlForPage (prefix ++ f) ++ "/"] << f
       updirs = drop 1 $ inits $ splitPath $ '/' : prefix
       uplink = foldr (\d accum ->
                   concatHtml [ anchor ! [theclass "updir",
                                          href $ if length d <= 1
                                                    then base' ++ "/_index"
-                                                   else base' ++ joinPath d] <<
+                                                   else base' ++ urlForPage (joinPath d)] <<
                   lastNote "fileListToHtml" d, accum]) noHtml updirs
   in uplink +++ ulist ! [theclass "index"] << map fileLink files
 
@@ -721,7 +723,7 @@
                 liftM extractCategories . (readFile . (repoPath </>))
   base' <- getWikiBase
   let toCatLink ctg = li <<
-        [ anchor ! [href $ base' ++ "/_category/" ++ ctg] << ctg ]
+        [ anchor ! [href $ base' ++ "/_category" ++ urlForPage ctg] << ctg ]
   let htmlMatches = ulist << map toCatLink categories
   formattedPage defaultPageLayout{
                   pgPageName = "Categories",
@@ -753,8 +755,10 @@
                    mbHost <- getHost
                    case mbHost of
                         Nothing    -> error "Could not determine base URL"
-                        Just hn    -> return ("http://" ++ hn ++ base')
-                 else return (baseUrl cfg ++ base')
+                        Just hn    -> return $ "http://" ++ hn ++ base'
+                 else case baseUrl cfg ++ base' of
+                           x@('h':'t':'t':'p':':':'/':'/':_) -> return x
+                           y                                 -> return $ "http://" ++ y
   let fc = FeedConfig{
               fcTitle = wikiTitle cfg
             , fcBaseUrl = feedBase
diff --git a/Network/Gitit/Layout.hs b/Network/Gitit/Layout.hs
--- a/Network/Gitit/Layout.hs
+++ b/Network/Gitit/Layout.hs
@@ -81,6 +81,7 @@
   let filledTemp = T.render .
                    T.setAttribute "base" base' .
                    T.setAttribute "feed" (pgLinkToFeed layout) .
+                   setStrAttr "wikititle" (wikiTitle cfg) .
                    setStrAttr "pagetitle" (pgTitle layout) .
                    T.setAttribute "javascripts" javascriptlinks .
                    setStrAttr "pagename" page .
diff --git a/Network/Gitit/Types.hs b/Network/Gitit/Types.hs
--- a/Network/Gitit/Types.hs
+++ b/Network/Gitit/Types.hs
@@ -42,7 +42,7 @@
 data PageType = Markdown | RST | LaTeX | HTML
                 deriving (Read, Show, Eq)
 
-data FileStoreType = Git | Darcs deriving Show
+data FileStoreType = Git | Darcs | Mercurial deriving Show
 
 data MathMethod = MathML | JsMathScript | RawTeX
                   deriving (Read, Show, Eq)
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -1,13 +1,13 @@
 Gitit
 =====
 
-Gitit is a wiki program written in Haskell. It uses [Happstack][]
-for the web server and [pandoc][] for markup processing. Pages and
-uploaded files are stored in a [git][] or [darcs][] 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
+Gitit is a wiki program written in Haskell. It uses [Happstack][] for
+the web server and [pandoc][] for markup processing. Pages and uploaded
+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][]).
@@ -35,6 +35,7 @@
 
 [git]: http://git.or.cz
 [darcs]: http://darcs.net
+[mercurial]: http://mercurial.selenic.com/
 [pandoc]: http://johnmacfarlane.net/pandoc
 [Happstack]: http://happstack.com
 [highlighting-kate]: http://johnmacfarlane.net/highlighting-kate/
@@ -99,8 +100,8 @@
 Running gitit
 -------------
 
-To run gitit, you'll need [git][] in your system path. (Or
-[darcs][], if you're using darcs to store the wiki data.)
+To run gitit, you'll need `git` in your system path. (Or `darcs` or
+`hg`, if you're using darcs or mercurial to store the wiki data.)
 
 Gitit assumes that the page files (stored in the git repository) are
 encoded as UTF-8. Even page names may be UTF-8 if the file system
@@ -246,7 +247,7 @@
 as well.  It will not be possible to modify these files using the web
 interface, but they will be modifiable via git.
 
-Using darcs instead of git
+Using a VCS other than git
 --------------------------
 
 By default, gitit will store wiki pages in a git repository in the
@@ -255,6 +256,10 @@
 
     repository-type: Darcs
 
+If you'd prefer to use mercurial, add:
+
+    repository-type: Mercurial
+
 This program may be called "darcsit" instead of "gitit" when a darcs
 backend is used.
 
@@ -339,22 +344,26 @@
 Note also that if you compile gitit for executable profiling, attempts
 to load plugins will result in "internal error: PAP object entered!"
 
-Accessing the wiki via git or darcs
-===================================
+Accessing the wiki through git
+==============================
 
-All the pages and uploaded files are stored in a git or darcs
-repository. By default, this lives in the `wikidata` directory (though
-this can be changed through configuration options). So you can interact
-with the wiki using git command line tools:
+All the pages and uploaded files are stored in a git repository. By
+default, this lives in the `wikidata` directory (though this can be
+changed through configuration options). So you can interact with the
+wiki using git command line tools:
 
     git clone ssh://my.server.edu/path/of/wiki/wikidata
     cd wikidata
     vim Front\ Page.page  # edit the page
     git commit -m "Added message about wiki etiquette" Front\ Page.page
-    git push 
+    git push
 
 If you now look at the Front Page on the wiki, you should see your changes
 reflected there.  Note that the pages all have the extension `.page`.
+
+If you are using the darcs or mercurial backend, the commands will
+be slightly different.  See the documentation for your VCS for
+details.
 
 Caching
 =======
diff --git a/data/default.conf b/data/default.conf
--- a/data/default.conf
+++ b/data/default.conf
@@ -3,9 +3,12 @@
 port: 5001
 # sets the port on which the web server will run.
 
+wiki-title: Wiki
+# the title of the wiki.
+
 repository-type: Git
 # specifies the type of repository used for wiki content.
-# Options are Git and Darcs.
+# Options are Git, Darcs, and Mercurial.
 
 repository-path: wikidata
 # specifies the path of the repository directory.  If it does not
@@ -200,9 +203,6 @@
 # request header 'Host'.  For most users, this should be fine, but
 # if you are proxying a gitit instance to a subdirectory URL, you will
 # want to set this manually.
-
-wiki-title: Wiki
-# the title of the wiki, used in feeds.
 
 feed-days: 14
 # number of days to be included in feeds.
diff --git a/data/static/css/base-min.css b/data/static/css/base-min.css
deleted file mode 100644
--- a/data/static/css/base-min.css
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-Copyright (c) 2009, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.net/yui/license.txt
-version: 2.7.0
-MODIFIED by JM - don't reset list item styles.
-*/
-body{margin:10px;}h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong,dt{font-weight:bold;}optgroup{font-weight:normal;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;}em{font-style:italic;}del{text-decoration:line-through;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{border:1px solid #000;padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}sup{vertical-align:super;}sub{vertical-align:sub;}p,fieldset,table,pre{margin-bottom:1em;}button,input[type="checkbox"],input[type="radio"],input[type="reset"],input[type="submit"]{padding:1px;}
diff --git a/data/static/css/reset-fonts-grids.css b/data/static/css/reset-fonts-grids.css
--- a/data/static/css/reset-fonts-grids.css
+++ b/data/static/css/reset-fonts-grids.css
@@ -3,6 +3,6 @@
 Code licensed under the BSD License:
 http://developer.yahoo.net/yui/license.txt
 version: 2.7.0
-MODIFIED by JM - don't reset list item styles
+MODIFIED by JM - don't reset list item styles, removed 'caption,th{text-align:left}'
 */
-html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}
+html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}
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
@@ -1,7 +1,7 @@
 @import url("reset-fonts-grids.css");
-@import url("base-min.css");
 
 html { background: #f9f9f9; color: black; } 
+body { margin: 10px; }
 
 fieldset { border: 1px solid #ccc; padding: 1em; }
 legend { font-weight: bold; margin-left: 1em; padding: 4px; }
@@ -27,9 +27,26 @@
 h5 { font-size: 108%; margin: 1.6em 0 .8em; }
 h6 { font-size: 100%; margin: 1.6em 0 .8em; }
 
+strong { font-weight: bold; }
 ul { list-style-type: square; }
 dt { font-weight: bold; margin-bottom: .1em; }
 
+optgroup{ font-weight: normal; }
+abbr, acronym { border-bottom:1px dotted #000; cursor:help; }
+em { font-style: italic; }
+del { text-decoration: line-through; }
+
+blockquote, ul, ol, dl { margin: 1em; }
+ol, ul, dl { margin-left: 2em; }
+dl dd { margin-left: 1em; }
+th, td { padding: .5em; }
+th { font-weight: bold; }
+caption { margin-bottom: .5em; text-align: center; }
+sup { vertical-align: super; }
+sub { vertical-align: sub; }
+p, fieldset, table, pre { margin-bottom: 1em; }
+button, input[type="checkbox"], input[type="radio"], input[type="reset"], input[type="submit"] { padding: 1px; }
+
 blockquote { padding: 0 1.6em; color: #666; }
 
 a:link { text-decoration: underline; color: #36c; }
@@ -90,6 +107,8 @@
 
 code { font-size: 93%; }
 pre.matches { margin: 0; padding: 0; }
+#pattern { background-color: yellow; font-weight: bold; }
+pre.matches span.highlighted { background-color: yellow; }
 
 .added { background-color: yellow; }
 .deleted { text-decoration: line-through; color: gray; }
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
@@ -1,5 +1,20 @@
+jQuery.fn.highlightPattern = function (patt, className)
+{
+    // 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');
+
+    return this.each(function ()
+    {
+        this.innerHTML = this.innerHTML.replace(regex,
+          '<span class=\'' + className + '\'>' + '$1' + '</span>');
+    });
+};
 function toggleMatches(obj) {
-  obj.next('.matches').slideToggle(300);
+  var pattern = $('#pattern').text();
+  var matches = obj.next('.matches')
+  matches.slideToggle(300);
+  matches.highlightPattern(pattern, 'highlighted');
   if (obj.html() == '[show matches]') {
       obj.html('[hide matches]');
     } else {
@@ -7,7 +22,7 @@
     };
   }
 $(function() {
-  $('a.showmatch').attr("onClick", "toggleMatches($(this));");
+  $('a.showmatch').attr('onClick', 'toggleMatches($(this));');
   $('pre.matches').hide();
   $('a.showmatch').show();
   });
diff --git a/data/templates/page.st b/data/templates/page.st
--- a/data/templates/page.st
+++ b/data/templates/page.st
@@ -4,10 +4,10 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     $if(feed)$
-    <link href="$base$/_feed" type="application/atom+xml" rel="alternate" title="Sitewide ATOM Feed" />
+    <link href="$base$/_feed/" type="application/atom+xml" rel="alternate" title="Sitewide ATOM Feed" />
     <link href="$base$/_feed$pageUrl$" type="application/atom+xml" rel="alternate" title="This page's ATOM Feed" />
     $endif$
-    <title>Wiki - $pagetitle$</title>
+    <title>$wikititle$ - $pagetitle$</title>
     $if(printable)$
     <link href="$base$/css/print.css" rel="stylesheet" media="all" type= "text/css" />
     $else$
diff --git a/data/templates/sitenav.st b/data/templates/sitenav.st
--- a/data/templates/sitenav.st
+++ b/data/templates/sitenav.st
@@ -9,7 +9,7 @@
       <li><a href="$base$/_activity">Recent activity</a></li>
       <li><a href="$base$/_upload">Upload a file</a></li>
       $if(feed)$
-      <li><a href="$base$/_feed" type="application/atom+xml" rel="alternate" title="ATOM Feed">Atom feed</a> <img alt="feed icon" src="$base$/img/icons/feed.png"/></li>
+      <li><a href="$base$/_feed/" type="application/atom+xml" rel="alternate" title="ATOM Feed">Atom feed</a> <img alt="feed icon" src="$base$/img/icons/feed.png"/></li>
       $endif$
       <li><a href="$base$/Help">Help</a></li>
     </ul>
diff --git a/gitit.cabal b/gitit.cabal
--- a/gitit.cabal
+++ b/gitit.cabal
@@ -1,10 +1,10 @@
 name:                gitit
-version:             0.6.6
+version:             0.7
 Cabal-version:       >= 1.2
 build-type:          Simple
 synopsis:            Wiki using happstack, git or darcs, and pandoc.
-description:         Gitit is a wiki backed by a git or darcs filestore.
-                     Pages and uploaded files can be modified either
+description:         Gitit is a wiki backed by a git, darcs, or mercurial
+                     filestore.  Pages and uploaded files can be modified either
                      directly via the VCS's command-line tools or through
                      the wiki's web interface. Pandoc is used for markup
                      processing, so pages may be written in
@@ -41,10 +41,10 @@
 maintainer:          jgm@berkeley.edu
 bug-reports:         http://code.google.com/p/gitit/issues/list
 homepage:            http://github.com/jgm/gitit/tree/master
-stability:           experimental 
+stability:           experimental
 data-files:          data/static/css/screen.css, data/static/css/print.css,
                      data/static/css/ie.css, data/static/css/hk-pyg.css,
-                     data/static/css/reset-fonts-grids.css, data/static/css/base-min.css,
+                     data/static/css/reset-fonts-grids.css,
                      data/static/css/custom.css,
                      data/static/img/logo.png, data/static/img/icons/feed.png,
                      data/static/img/icons/folder.png, data/static/img/icons/page.png,
@@ -98,7 +98,7 @@
     exposed-modules: Network.Gitit.Interface
     build-depends:   ghc, ghc-paths
     cpp-options:     -D_PLUGINS
-  build-depends:     base >= 3, pandoc >= 1.1, filepath, safe
+  build-depends:     base >= 3, pandoc >= 1.3, filepath, safe
   ghc-options:       -Wall
   ghc-prof-options:  -auto-all -caf-all
 
@@ -109,9 +109,9 @@
                      pandoc >= 1.2, process, filepath, directory, mtl, cgi,
                      network, old-time, highlighting-kate, bytestring,
                      utf8-string, SHA > 1, HTTP, HStringTemplate, random,
-                     network >= 2.1.0.0, recaptcha >= 0.1, filestore >= 0.3.3,
-                     datetime, zlib, url, happstack-server >= 0.3.3 && < 0.4,
-                     happstack-util >= 0.3.2 && < 0.4, xml >= 1.3.4,
+                     network >= 2.1.0.0, recaptcha >= 0.1, filestore >= 0.3.4,
+                     datetime, zlib, url, happstack-server >= 0.3.3 && < 0.5,
+                     happstack-util >= 0.3.2 && < 0.5, xml >= 1.3.5,
                      hslogger >= 1 && < 1.1, ConfigFile >= 1, feed >= 0.3.6,
                      cautious-file >= 0.1.5 && < 0.2, texmath
   if impl(ghc >= 6.10)
diff --git a/gitit.hs b/gitit.hs
--- a/gitit.hs
+++ b/gitit.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-
 Copyright (C) 2008 John MacFarlane <jgm@berkeley.edu>
 
@@ -23,22 +24,34 @@
 import Network.Gitit.Initialize (createStaticIfMissing, createRepoIfMissing)
 import Prelude hiding (writeFile, readFile, catch)
 import System.Directory
-import Network.Gitit.Config (getConfigFromOpts)
+import Network.Gitit.Config (getConfigFromFile)
 import Data.Maybe (isNothing)
 import Control.Monad.Reader
 import System.Log.Logger (Priority(..), setLevel, setHandlers,
         getLogger, saveGlobalLogger)
 import System.Log.Handler.Simple (fileHandler)
-import Data.Char (toLower)
+import System.Environment
+import System.Exit
+import System.IO (stdout, stderr)
+import System.Console.GetOpt
+import Data.Version (showVersion)
+import Prelude hiding (readFile)
+import System.IO.UTF8
+import Paths_gitit (version, getDataFileName)
 
 main :: IO ()
 main = do
 
   -- parse options to get config file
-  conf <- getConfigFromOpts
+  opts <- getArgs >>= parseArgs
+  defaultConfig <- getDefaultConfig
+  conf <- foldM handleFlag defaultConfig opts
 
   -- check for external programs that are needed
-  let repoProg = map toLower $ show $ repositoryType conf
+  let repoProg = case repositoryType conf of
+                       Mercurial   -> "hg"
+                       Darcs       -> "darcs"
+                       Git         -> "git"
   let prereqs = ["grep", repoProg]
   forM_ prereqs $ \prog ->
     findExecutable prog >>= \mbFind ->
@@ -64,8 +77,71 @@
   initializeGititState conf'
 
   let serverConf = Conf { validator = Nothing, port = portNumber conf' }
+
   -- start the server
-  simpleHTTP serverConf $ msum [
-      wiki conf'
-    , dir "_reloadTemplates" reloadTemplates
-    ]
+  simpleHTTP serverConf $ msum [ wiki conf'
+                               , dir "_reloadTemplates" reloadTemplates
+                               ]
+
+data Opt
+    = Help
+    | ConfigFile FilePath
+    | Port Int
+    | Debug
+    | Version
+    | PrintDefaultConfig
+    deriving (Eq)
+
+flags :: [OptDescr Opt]
+flags =
+   [ Option ['h'] ["help"] (NoArg Help)
+        "Print this help message"
+   , Option ['v'] ["version"] (NoArg Version)
+        "Print version information"
+   , Option ['p'] ["port"] (ReqArg (Port . read) "PORT")
+        "Specify port"
+   , Option [] ["print-default-config"] (NoArg PrintDefaultConfig)
+        "Print default configuration"
+   , Option [] ["debug"] (NoArg Debug)
+        "Print debugging information on each request"
+   , Option ['f'] ["config-file"] (ReqArg ConfigFile "FILE")
+        "Specify configuration file"
+   ]
+
+parseArgs :: [String] -> IO [Opt]
+parseArgs argv = do
+  progname <- getProgName
+  case getOpt Permute flags argv of
+    (opts,_,[])  -> return opts
+    (_,_,errs)   -> hPutStrLn stderr (concat errs ++ usageInfo (usageHeader progname) flags) >>
+                       exitWith (ExitFailure 1)
+
+usageHeader :: String -> String
+usageHeader progname = "Usage:  " ++ progname ++ " [opts...]"
+
+copyrightMessage :: String
+copyrightMessage = "\nCopyright (C) 2008 John MacFarlane\n" ++
+                   "This is free software; see the source for copying conditions.  There is no\n" ++
+                   "warranty, not even for merchantability or fitness for a particular purpose."
+
+compileInfo :: String
+compileInfo =
+#ifdef _PLUGINS
+  " +plugins"
+#else
+  " -plugins"
+#endif
+
+handleFlag :: Config -> Opt -> IO Config
+handleFlag conf opt = do
+  progname <- getProgName
+  case opt of
+    Help               -> hPutStrLn stderr (usageInfo (usageHeader progname) flags) >> exitWith ExitSuccess
+    Version            -> hPutStrLn stderr (progname ++ " version " ++ showVersion version ++ compileInfo ++ copyrightMessage) >> exitWith ExitSuccess
+    PrintDefaultConfig -> getDataFileName "data/default.conf" >>= readFile >>=
+                          hPutStrLn stdout >> exitWith ExitSuccess
+    Debug              -> return conf{ debugMode = True }
+    Port p             -> return conf{ portNumber = p }
+    ConfigFile fname   -> getConfigFromFile fname
+
+
diff --git a/plugins/Interwiki.hs b/plugins/Interwiki.hs
--- a/plugins/Interwiki.hs
+++ b/plugins/Interwiki.hs
@@ -49,12 +49,20 @@
     _ -> Link ref (interwiki, article)
 convertInterwikiLinks x = x
 
-{- | Large table of constants; this is a mapping from shortcuts to a URL. The URL can be used by
-   appending to it the article name (suitably URL-escaped, of course).
-   The mapping is derived from <https://secure.wikimedia.org/wikipedia/meta/wiki/Interwiki_map>
-   as of 11:19 PM, 11 February 2009. -}
+-- | Large table of constants; this is a mapping from shortcuts to a URL. The URL can be used by
+--   appending to it the article name (suitably URL-escaped, of course).
 interwikiMap :: M.Map String String
-interwikiMap = M.fromList [ ("AbbeNormal", "http://ourpla.net/cgi/pikie?"),
+interwikiMap = M.fromList $ wpInterwikiMap ++ customInterwikiMap
+
+wpInterwikiMap, customInterwikiMap :: [(String, String)]
+customInterwikiMap = [("Hackage", "http://hackage.haskell.org/package/"),
+                      ("Hawiki", "http://haskell.org/haskellwiki/"),
+                      ("Hayoo", "http://holumbus.fh-wedel.de/hayoo/hayoo.html#0:"),
+                      ("Hoogle", "http://www.haskell.org/hoogle/?hoogle=")]
+
+-- This mapping is derived from <https://secure.wikimedia.org/wikipedia/meta/wiki/Interwiki_map>
+-- as of 11:19 PM, 11 February 2009.
+wpInterwikiMap = [ ("AbbeNormal", "http://ourpla.net/cgi/pikie?"),
                  ("Acronym", "http://www.acronymfinder.com/af-query.asp?String=exact&Acronym="),
                  ("Advisory", "http://advisory.wikimedia.org/wiki/"),
                  ("Advogato", "http://www.advogato.org/"),
diff --git a/plugins/WebArchiver.hs b/plugins/WebArchiver.hs
--- a/plugins/WebArchiver.hs
+++ b/plugins/WebArchiver.hs
@@ -1,22 +1,27 @@
--- | Scans page of Markdown looking for http links. When it finds them, it submits them
--- to webcitation.org / https://secure.wikimedia.org/wikipedia/en/wiki/WebCite
---
--- Limitations:
--- * Only parses Markdown, not ReST or any other format; this is because 'readMarkdown'
--- is hardwired into it.
---
--- By: Gwern Branwen; placed in the public domain
+{-| Scans page of Markdown looking for http links. When it finds them, it submits them
+to webcitation.org / https://secure.wikimedia.org/wikipedia/en/wiki/WebCite
+(It will also submit them to Alexa (the source for the Internet Archive), but Alexa says that
+its bots take weeks to visit and may not ever.)
 
+Limitations:
+* Only parses Markdown, not ReST or any other format; this is because 'readMarkdown'
+is hardwired into it.
+
+By: Gwern Branwen; placed in the public domain -}
+
 module WebArchiver (plugin) where
 
-import Network.Gitit.Interface (askUser, liftIO, processWithM, uEmail, Plugin(PreCommitTransform), Inline(Link))
+import Control.Concurrent (forkIO, ThreadId)
 import Control.Monad (when)
-import Network.URI (isURI)
-import Control.Concurrent (forkIO)
-import Network.HTTP (getRequest, simpleHTTP)
-import Text.Pandoc (defaultParserState, readMarkdown)
 import Control.Monad.Trans (MonadIO)
+import Data.Maybe (fromJust)
+import Network.Browser (browse, formToRequest, request, Form(..))
+import Network.HTTP (getRequest, rspBody, simpleHTTP, RequestMethod(POST))
+import Network.URI (isURI, parseURI, uriPath)
 
+import Network.Gitit.Interface (askUser, liftIO, processWithM, uEmail, Plugin(PreCommitTransform), Inline(Link))
+import Text.Pandoc (defaultParserState, readMarkdown)
+
 plugin :: Plugin
 plugin = PreCommitTransform archivePage
 
@@ -32,12 +37,20 @@
 
 archiveLinks :: String -> Inline -> IO Inline
 archiveLinks e x@(Link _ (uln, _)) = checkArchive e uln >> return x
-archiveLinks _ x = return x
+archiveLinks _ x                   = return x
 
--- | Error check the URL.
+-- | Error check the URL and then archive it both ways
 checkArchive :: (MonadIO m) => String -> String -> m ()
-checkArchive e u = when (isURI u) (liftIO $ archiveURL e u)
+checkArchive email url = when (isURI url) $ liftIO (webciteArchive email url >> alexaArchive url)
 
-archiveURL :: String -> String -> IO ()
-archiveURL eml url = forkIO (openURL ("http://www.webcitation.org/archive?url=" ++ url ++ "&email=" ++ eml) >> return ()) >> return ()
+webciteArchive :: String -> String -> IO ThreadId
+webciteArchive email url = forkIO (ignore $ openURL ("http://www.webcitation.org/archive?url=" ++ url ++ "&email=" ++ email))
    where openURL = simpleHTTP . getRequest
+         ignore = fmap $ const ()
+
+alexaArchive :: String -> IO ()
+alexaArchive url = do let archiveform = Form POST (fromJust $ parseURI "http://www.alexa.com/help/crawlrequest")
+                                                                             [("url", url), ("submit", "")]
+                      (uri, resp) <- browse $ request $ formToRequest archiveform
+                      when (uriPath uri /= "/help/crawlthanks") $
+                           error $ "Request failed! Did Alexa change webpages? Response:" ++ rspBody resp
