diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,15 @@
+Version 0.9.0.1 released 15 Feb 2012
+
+*   Fixed bug in fromEntities that caused text to be lost in the page
+    source after semicolons.  Thanks to Perry Wagle for reporting the bug.
+
+*   Updated code to run on happstack 7.
+
+*   Removed dependency on happstack-util; depend on base64-bytestring
+    instead.
+
+*   Updated gitit.cabal to include footnotes.js (Ben Sinclair).
+
 Version 0.9 released 29 Feb 2012
 
 *   Gitit now uses the latest pandoc (1.9.x) and happstack-server (6.6.x),
diff --git a/Network/Gitit/Framework.hs b/Network/Gitit/Framework.hs
--- a/Network/Gitit/Framework.hs
+++ b/Network/Gitit/Framework.hs
@@ -62,8 +62,8 @@
 import Data.Char (toLower)
 import Control.Monad (mzero, liftM, unless, MonadPlus)
 import qualified Data.Map as M
-import Data.ByteString.UTF8 (toString)
-import Data.ByteString.Lazy.UTF8 (fromString)
+import qualified Data.ByteString.UTF8 as UTF8
+import qualified Data.ByteString.Lazy.UTF8 as LazyUTF8
 import Data.Maybe (fromJust, fromMaybe)
 import Data.List (intercalate, isPrefixOf, isInfixOf)
 import System.FilePath ((<.>), takeExtension, takeFileName)
@@ -71,7 +71,7 @@
 import Text.ParserCombinators.Parsec
 import Network.URL (decString, encString)
 import Network.URI (isUnescapedInURI)
-import Happstack.Crypto.Base64 (decode)
+import Data.ByteString.Base64 (decodeLenient)
 import Network.HTTP (urlEncodeVars)
 
 -- | Require a logged in user if the authentication level demands it.
@@ -117,7 +117,7 @@
   req <- askRq
   let user = case getHeader "authorization" req of
               Nothing         -> ""
-              Just authHeader -> case parse pAuthorizationHeader "" (toString authHeader) of
+              Just authHeader -> case parse pAuthorizationHeader "" (UTF8.toString authHeader) of
                                   Left _  -> ""
                                   Right u -> u
   localRq (setHeader "REMOTE_USER" user) handler
@@ -126,7 +126,7 @@
 getLoggedInUser :: GititServerPart (Maybe User)
 getLoggedInUser = do
   req <- askRq
-  case maybe "" toString (getHeader "REMOTE_USER" req) of
+  case maybe "" UTF8.toString (getHeader "REMOTE_USER" req) of
         "" -> return Nothing
         u  -> do
           mbUser <- getUser u
@@ -148,7 +148,8 @@
 pBasicHeader = do
   _ <- string "Basic "
   result' <- many (noneOf " \t\n")
-  return $ takeWhile (/=':') $ decode result'
+  return $ takeWhile (/=':') $ UTF8.toString
+         $ decodeLenient $ UTF8.fromString result'
 
 -- | @unlessNoEdit responder fallback@ runs @responder@ unless the
 -- page has been designated not editable in configuration; in that
@@ -197,7 +198,7 @@
   req <- askRq
   base' <- getWikiBase
   return $ case getHeader "referer" req of
-                 Just r  -> case toString r of
+                 Just r  -> case UTF8.toString r of
                                  ""  -> base'
                                  s   -> s
                  Nothing -> base'
@@ -327,7 +328,8 @@
   req <- askRq
   let inps = filter (\(n,_) -> n /= "messages") $ rqInputsQuery req
   let newInp = ("messages", Input {
-                              inputValue = Right $ fromString $ show messages
+                              inputValue = Right
+                                         $ LazyUTF8.fromString $ show messages
                             , inputFilename = Nothing
                             , inputContentType = ContentType {
                                     ctType = "text"
diff --git a/Network/Gitit/Types.hs b/Network/Gitit/Types.hs
--- a/Network/Gitit/Types.hs
+++ b/Network/Gitit/Types.hs
@@ -36,6 +36,7 @@
 import Data.FileStore.Types
 import Network.Gitit.Server
 import Text.HTML.TagSoup.Entity (lookupEntity)
+import Data.Char (isSpace)
 
 data PageType = Markdown | RST | LaTeX | HTML | Textile
                 deriving (Read, Show, Eq)
@@ -398,8 +399,8 @@
 fromEntities ('&':xs) =
   case lookupEntity ent of
         Just c  -> c : fromEntities rest
-        Nothing -> '&' : fromEntities rest
-    where (ent, rest) = case break (==';') xs of
+        Nothing -> '&' : fromEntities xs
+    where (ent, rest) = case break (\c -> isSpace c || c == ';') xs of
                              (zs,';':ys) -> (zs,ys)
                              _           -> ("",xs)
 fromEntities (x:xs) = x : fromEntities xs
diff --git a/data/static/js/footnotes.js b/data/static/js/footnotes.js
new file mode 100644
--- /dev/null
+++ b/data/static/js/footnotes.js
@@ -0,0 +1,63 @@
+$(document).ready(function() {
+    Footnotes.setup();
+});
+
+var Footnotes = {
+    footnotetimeout: false,
+    setup: function() {
+        var footnotelinks = $('.footnoteRef')
+
+        footnotelinks.unbind('mouseover',Footnotes.footnoteover);
+        footnotelinks.unbind('mouseout',Footnotes.footnoteoout);
+
+        footnotelinks.bind('mouseover',Footnotes.footnoteover);
+        footnotelinks.bind('mouseout',Footnotes.footnoteoout);
+    },
+    footnoteover: function() {
+        clearTimeout(Footnotes.footnotetimeout);
+        $('#footnotediv').stop();
+        $('#footnotediv').remove();
+
+        var id = $(this).attr('href').substr(1);
+        var position = $(this).offset();
+
+        var div = $(document.createElement('div'));
+        div.attr('id','footnotediv');
+        div.bind('mouseover',Footnotes.divover);
+        div.bind('mouseout',Footnotes.footnoteoout);
+
+        var el = document.getElementById(id);
+        div.html('<div>'+$(el).html()+'</div>');
+
+        $(document.body).append(div);
+
+        var left = position.left;
+        if(left + 420  > $(window).width() + $(window).scrollLeft())
+            left = $(window).width() - 420 + $(window).scrollLeft();
+        var top = position.top+20;
+        if(top + div.height() > $(window).height() + $(window).scrollTop())
+            top = position.top - div.height() - 15;
+        div.css({
+            left:left,
+            top:top,
+            opacity:0.95,
+            position: "absolute"
+            });
+    },
+    footnoteoout: function() {
+        Footnotes.footnotetimeout = setTimeout(function() {
+            $('#footnotediv').animate({
+                opacity: 0
+            }, 600, function() {
+                $('#footnotediv').remove();
+            });
+        },100);
+    },
+    divover: function() {
+        clearTimeout(Footnotes.footnotetimeout);
+        $('#footnotediv').stop();
+        $('#footnotediv').css({
+                opacity: 0.9
+        });
+    }
+}
diff --git a/gitit.cabal b/gitit.cabal
--- a/gitit.cabal
+++ b/gitit.cabal
@@ -1,5 +1,5 @@
 name:                gitit
-version:             0.9
+version:             0.9.0.1
 Cabal-version:       >= 1.6
 build-type:          Simple
 synopsis:            Wiki using happstack, git or darcs, and pandoc.
@@ -52,7 +52,7 @@
                      data/static/js/uploadForm.js, data/static/js/jquery-ui.packed.js,
                      data/static/js/jquery.hotkeys-0.7.9.min.js,
                      data/static/js/preview.js, data/static/js/search.js,
-                     data/static/js/MathMLinHTML.js,
+                     data/static/js/MathMLinHTML.js, data/static/js/footnotes.js,
                      data/static/robots.txt,
                      data/s5/default/blank.gif,
                      data/s5/default/bodybg.gif,
@@ -157,8 +157,8 @@
                      filestore >= 0.4.0.2 && < 0.5,
                      zlib >= 0.5 && < 0.6,
                      url >= 2.1 && < 2.2,
-                     happstack-server >= 6.6 && < 6.7,
-                     happstack-util >= 6.0 && < 6.1,
+                     happstack-server >= 6.6 && < 7.1,
+                     base64-bytestring >= 0.1 && < 0.2,
                      xml >= 1.3.5,
                      hslogger >= 1 && < 1.2,
                      ConfigFile >= 1 && < 1.2,
