diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Main
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley@edu>
@@ -104,6 +104,7 @@
     , optStrict            :: Bool    -- ^ Use strict markdown syntax
     , optReferenceLinks    :: Bool    -- ^ Use reference links in writing markdown, rst
     , optWrapText          :: Bool    -- ^ Wrap text
+    , optSanitizeHTML      :: Bool    -- ^ Sanitize HTML
     }
 
 -- | Defaults for command-line options.
@@ -132,6 +133,7 @@
     , optStrict            = False
     , optReferenceLinks    = False
     , optWrapText          = True
+    , optSanitizeHTML      = False
     }
 
 -- | A list of functions, each transforming the options data structure
@@ -226,6 +228,11 @@
                   (\opt -> return opt { optWrapText = False }))
                  "" -- "Do not wrap text in output"
 
+    , Option "" ["sanitize-html"]
+                 (NoArg
+                  (\opt -> return opt { optSanitizeHTML = True }))
+                 "" -- "Sanitize HTML"
+
     , Option "" ["toc", "table-of-contents"]
                 (NoArg
                  (\opt -> return opt { optTableOfContents = True }))
@@ -241,8 +248,9 @@
     , Option "H" ["include-in-header"]
                  (ReqArg
                   (\arg opt -> do
+                     let old = optIncludeInHeader opt
                      text <- readFile arg
-                     return opt { optIncludeInHeader = fromUTF8 text, 
+                     return opt { optIncludeInHeader = old ++ fromUTF8 text, 
                                   optStandalone = True })
                   "FILENAME")
                  "" -- "File to include at end of header (implies -s)"
@@ -250,16 +258,18 @@
     , Option "B" ["include-before-body"]
                  (ReqArg
                   (\arg opt -> do
+                     let old = optIncludeBeforeBody opt
                      text <- readFile arg
-                     return opt { optIncludeBeforeBody = fromUTF8 text })
+                     return opt { optIncludeBeforeBody = old ++ fromUTF8 text })
                   "FILENAME")
                  "" -- "File to include before document body"
 
     , Option "A" ["include-after-body"]
                  (ReqArg
                   (\arg opt -> do
+                     let old = optIncludeAfterBody opt
                      text <- readFile arg
-                     return opt { optIncludeAfterBody = fromUTF8 text })
+                     return opt { optIncludeAfterBody = old ++ fromUTF8 text })
                   "FILENAME")
                  "" -- "File to include after document body"
 
@@ -421,6 +431,7 @@
               , optStrict            = strict
               , optReferenceLinks    = referenceLinks
               , optWrapText          = wrap
+              , optSanitizeHTML      = sanitize
              } = opts
 
   if dumpArgs
@@ -473,13 +484,14 @@
         x:(tabFilter (spsToNextStop - 1) xs)
 
   let startParserState = 
-         defaultParserState { stateParseRaw    = parseRaw,
-                              stateTabStop     = tabStop, 
-                              stateStandalone  = standalone && (not strict),
-                              stateSmart       = smart || writerName' `elem` 
-                                                          ["latex", "context"],
-                              stateColumns     = columns,
-                              stateStrict      = strict }
+         defaultParserState { stateParseRaw     = parseRaw,
+                              stateTabStop      = tabStop, 
+                              stateSanitizeHTML = sanitize,
+                              stateStandalone   = standalone && (not strict),
+                              stateSmart        = smart || writerName' `elem` 
+                                                           ["latex", "context"],
+                              stateColumns      = columns,
+                              stateStrict       = strict }
   let csslink = if (css == "")
                    then "" 
                    else "<link rel=\"stylesheet\" href=\"" ++ css ++ 
diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
 % Pandoc User's Guide
 % John MacFarlane
-% August 15, 2007
+% January 8, 2008
 
 Pandoc is a [Haskell] library for converting from one markup format to
 another, and a command-line tool that uses this library. It can read
@@ -345,6 +345,11 @@
 :   disables text-wrapping in output.  By default, text is wrapped
     appropriately for the output format.
 
+`--sanitize-html`
+:   sanitizes HTML (in markdown or HTML input) using a whitelist.
+    Unsafe tags are replaced by HTML comments; unsafe attributes
+    are omitted.
+
 `--dump-args`
 :   is intended to make it easier to create wrapper scripts that use
     Pandoc. It causes Pandoc to dump information about the arguments
@@ -790,13 +795,20 @@
   - Remove all punctuation, except dashes and hyphens.
   - Replace all spaces, dashes, newlines, and hyphens with hyphens.
   - Convert all alphabetic characters to lowercase.
+  - Remove everything up to the first letter (identifiers may
+    not begin with a number or punctuation mark).
+  - If nothing is left after this, use the identifier `section`.
 
-Thus, for example, a heading 'Header identifiers in HTML' will get
-the identifier `header-identifiers-in-html`, a heading
-'*Dogs*?--in *my* house?' will get the identifier `dogs--in-my-house`,
-and a heading '[HTML], [S5], or [RTF]?' will get the identifier
-`html-s5-or-rtf`.
+Thus, for example,
 
+  Header                                  Identifier
+  -------------------------------------   ---------------------------
+  Header identifiers in HTML              `header-identifiers-in-html`
+  *Dogs*?--in *my* house?                 `dogs--in-my-house`
+  [HTML], [S5], or [RTF]?                 `html-s5-or-rtf`
+  3. Applications                         `applications`
+  33                                      `section`
+
 These rules should, in most cases, allow one to determine the identifier
 from the header text. The exception is when several headers have the
 same text; in this case, the first will get an identifier as described
@@ -839,6 +851,10 @@
 TeX math will be printed in all output formats. In Markdown,
 reStructuredText, LaTeX, and ConTeXt output, it will appear verbatim
 between $ characters.
+
+In reStructuredText output, it will be rendered using an interpreted
+text role `:math:`, as described
+[here](http://www.american.edu/econ/itex2mml/mathhack.rst).
 
 In groff man output, it will be rendered verbatim without $'s.
 
diff --git a/RELEASE-CHECKLIST b/RELEASE-CHECKLIST
new file mode 100644
--- /dev/null
+++ b/RELEASE-CHECKLIST
@@ -0,0 +1,39 @@
+_ Test: make build-all, make install-all, make uninstall-all, 
+        make deb, run website demos, test on windows, test on mac
+
+_ Finalize debian changelog
+
+_ Tag release
+    svn copy https://pandoc.googlecode.com/svn/trunk https://pandoc.googlecode.com/svn/tags/pandoc-x.yy
+
+_ Generate tarball (make tarball)
+
+_ Generate Windows package and copy to directory
+
+_ Upload to Google Code
+    googlecode-upload.py -s "Source tarball" -p pandoc -u fiddlosopher --labels=Featured,Type-Source,OpSys-All  pandoc-x.yy.tar.gz
+    googlecode-upload.py -s "Windows binary package" -p pandoc -u fiddlosopher --labels=Featured,Type-Archive,OpSys-Windows  pandoc-x.yy.zip
+
+_ Go to Google code and deprecate the old versions
+
+_ Upload to HackageDB
+
+_ email roktas to upload to debian
+
+_ make macport, test on a mac
+
+_ submit change request to MacPorts launchpad
+    http://guide.macports.org/#project.update-policies
+
+_ make FreeBSD port, test on FreeBSD
+
+_ submit change request to FreeBSD 
+    http://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/port-upgrading.html
+    http://www.freebsd.org/send-pr.html
+
+_ Update website, including short description of changes
+
+_ Announce on pandoc-announce, pandoc-discuss
+
+_ Update freshmeat page
+
diff --git a/Text/Pandoc.hs b/Text/Pandoc.hs
--- a/Text/Pandoc.hs
+++ b/Text/Pandoc.hs
@@ -107,4 +107,4 @@
 
 -- | Version number of pandoc library.
 pandocVersion :: String
-pandocVersion = "0.45"
+pandocVersion = "0.46"
diff --git a/Text/Pandoc/Readers/HTML.hs b/Text/Pandoc/Readers/HTML.hs
--- a/Text/Pandoc/Readers/HTML.hs
+++ b/Text/Pandoc/Readers/HTML.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Readers.HTML
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
@@ -60,7 +60,7 @@
 --
 
 eitherBlockOrInline = ["applet", "button", "del", "iframe", "ins",
-                  "map", "area", "object", "script"]
+                  "map", "area", "object"]
 
 inlineHtmlTags = ["a", "abbr", "acronym", "b", "basefont", "bdo", "big",
                   "br", "cite", "code", "dfn", "em", "font", "i", "img",
@@ -73,12 +73,56 @@
                  "h5", "h6", "hr", "isindex", "menu", "noframes",
                  "noscript", "ol", "p", "pre", "table", "ul", "dd",
                  "dt", "frameset", "li", "tbody", "td", "tfoot",
-                 "th", "thead", "tr"] ++ eitherBlockOrInline
+                 "th", "thead", "tr", "script"] ++ eitherBlockOrInline
 
+sanitaryTags = ["a", "abbr", "acronym", "address", "area", "b", "big",
+                "blockquote", "br", "button", "caption", "center",
+                "cite", "code", "col", "colgroup", "dd", "del", "dfn",
+                "dir", "div", "dl", "dt", "em", "fieldset", "font",
+                "form", "h1", "h2", "h3", "h4", "h5", "h6", "hr",
+                "i", "img", "input", "ins", "kbd", "label", "legend",
+                "li", "map", "menu", "ol", "optgroup", "option", "p",
+                "pre", "q", "s", "samp", "select", "small", "span",
+                "strike", "strong", "sub", "sup", "table", "tbody",
+                "td", "textarea", "tfoot", "th", "thead", "tr", "tt",
+                "u", "ul", "var"]
+
+sanitaryAttributes = ["abbr", "accept", "accept-charset",
+                      "accesskey", "action", "align", "alt", "axis",
+                      "border", "cellpadding", "cellspacing", "char",
+                      "charoff", "charset", "checked", "cite", "class",
+                      "clear", "cols", "colspan", "color", "compact",
+                      "coords", "datetime", "dir", "disabled",
+                      "enctype", "for", "frame", "headers", "height",
+                      "href", "hreflang", "hspace", "id", "ismap",
+                      "label", "lang", "longdesc", "maxlength", "media",
+                      "method", "multiple", "name", "nohref", "noshade",
+                      "nowrap", "prompt", "readonly", "rel", "rev",
+                      "rows", "rowspan", "rules", "scope", "selected",
+                      "shape", "size", "span", "src", "start",
+                      "summary", "tabindex", "target", "title", "type",
+                      "usemap", "valign", "value", "vspace", "width"]
+
 --
 -- HTML utility functions
 --
 
+-- | Returns @True@ if sanitization is specified and the specified tag is 
+--  not on the sanitized tag list.
+unsanitaryTag tag = do
+  st <- getState
+  if stateSanitizeHTML st && not (tag `elem` sanitaryTags)
+     then return True
+     else return False
+
+-- | returns @True@ if sanitization is specified and the specified attribute
+--  is not on the sanitized attribute list.
+unsanitaryAttribute (attr, _, _) = do
+  st <- getState
+  if stateSanitizeHTML st && not (attr `elem` sanitaryAttributes)
+    then return True
+    else return False
+
 -- | Read blocks until end tag.
 blocksTilEnd tag = do
   blocks <- manyTill (block >>~ spaces) (htmlEndTag tag)
@@ -111,20 +155,28 @@
   let ender' = if null ender then "" else " /"
   spaces
   char '>'
-  return $ "<" ++ tag ++ 
-           concatMap (\(_, _, raw) -> (' ':raw)) attribs ++ ender' ++ ">"
+  let result = "<" ++ tag ++ 
+               concatMap (\(_, _, raw) -> (' ':raw)) attribs ++ ender' ++ ">"
+  unsanitary <- unsanitaryTag tag
+  if unsanitary
+     then return $ "<!-- unsafe HTML removed -->"
+     else return result
 
 anyHtmlEndTag = try $ do
   char '<'   
   spaces
   char '/'
   spaces
-  tagType <- many1 alphaNum
+  tag <- many1 alphaNum
   spaces
   char '>'
-  return $ "</" ++ tagType ++ ">"
+  let result = "</" ++ tag ++ ">"
+  unsanitary <- unsanitaryTag tag
+  if unsanitary
+     then return $ "<!-- unsafe HTML removed -->"
+     else return result 
 
-htmlTag :: String -> GenParser Char st (String, [(String, String)])
+htmlTag :: String -> GenParser Char ParserState (String, [(String, String)])
 htmlTag tag = try $ do
   char '<'
   spaces
@@ -142,8 +194,15 @@
                     (many (noneOf [quoteChar]))
   return (result, [quoteChar])
 
-htmlAttribute = htmlRegularAttribute <|> htmlMinimizedAttribute
+nullAttribute = ("", "", "") 
 
+htmlAttribute = do
+  attr <- htmlRegularAttribute <|> htmlMinimizedAttribute
+  unsanitary <- unsanitaryAttribute attr
+  if unsanitary
+     then return nullAttribute
+     else return attr
+
 -- minimized boolean attribute
 htmlMinimizedAttribute = try $ do
   many1 space
@@ -183,7 +242,7 @@
 
 anyHtmlBlockTag = try $ do
   tag <- anyHtmlTag <|> anyHtmlEndTag
-  if isBlock tag then return tag else fail "inline tag"
+  if not (isInline tag) then return tag else fail "not a block tag"
 
 anyHtmlInlineTag = try $ do
   tag <- anyHtmlTag <|> anyHtmlEndTag
@@ -194,17 +253,33 @@
 htmlScript = try $ do
   open <- string "<script"
   rest <- manyTill anyChar (htmlEndTag "script")
-  return $ open ++ rest ++ "</script>"
+  st <- getState
+  if stateSanitizeHTML st && not ("script" `elem` sanitaryTags)
+     then return "<!-- unsafe HTML removed -->"
+     else return $ open ++ rest ++ "</script>"
 
-htmlBlockElement = choice [ htmlScript, htmlComment, xmlDec, definition ]
+-- | Parses material between style tags.
+-- Style tags must be treated differently, because they can contain CSS
+htmlStyle = try $ do
+  open <- string "<style"
+  rest <- manyTill anyChar (htmlEndTag "style")
+  st <- getState
+  if stateSanitizeHTML st && not ("style" `elem` sanitaryTags)
+     then return "<!-- unsafe HTML removed -->"
+     else return $ open ++ rest ++ "</style>"
 
+htmlBlockElement = choice [ htmlScript, htmlStyle, htmlComment, xmlDec, definition ]
+
 rawHtmlBlock = try $ do
-  notFollowedBy' (htmlTag "/body" <|> htmlTag "/html")
-  body <- htmlBlockElement <|> anyHtmlTag <|> anyHtmlEndTag
-  sp <- many space
+  body <- htmlBlockElement <|> anyHtmlBlockTag
   state <- getState
-  if stateParseRaw state then return (RawHtml (body ++ sp)) else return Null
+  if stateParseRaw state then return (RawHtml body) else return Null
 
+-- We don't want to parse </body> or </html> as raw HTML, since these
+-- are handled in parseHtml.
+rawHtmlBlock' = do notFollowedBy' (htmlTag "/body" <|> htmlTag "/html")
+                   rawHtmlBlock
+
 -- | Parses an HTML comment.
 htmlComment = try $ do
   string "<!--"
@@ -225,8 +300,10 @@
   rest <- manyTill anyChar (char '>')
   return $ "<!" ++ rest ++ ">"
 
-nonTitleNonHead = try $ notFollowedBy' (htmlTag "title" <|> htmlTag "/head") >>
-  ((rawHtmlBlock >> return ' ') <|> anyChar)
+nonTitleNonHead = try $ do
+  notFollowedBy $ (htmlTag "title" >> return ' ') <|> 
+                  (htmlEndTag "head" >> return ' ')
+  (rawHtmlBlock >> return ' ') <|> anyChar
 
 parseTitle = try $ do
   (tag, _) <- htmlTag "title"
@@ -241,7 +318,7 @@
   skipMany nonTitleNonHead
   contents <- option [] parseTitle
   skipMany nonTitleNonHead
-  htmlTag "/head"
+  htmlEndTag "head"
   return (contents, [], "")
 
 skipHtmlTag tag = optional (htmlTag tag)
@@ -284,7 +361,8 @@
                , blockQuote
                , para
                , plain
-               , rawHtmlBlock ] <?> "block"
+               , rawHtmlBlock'
+               ] <?> "block"
 
 --
 -- header blocks
@@ -430,14 +508,14 @@
                   joinWithSep " " $ lines result 
 
 rawHtmlInline = do
-  result <- htmlScript <|> htmlComment <|> anyHtmlInlineTag
+  result <- htmlScript <|> htmlStyle <|> htmlComment <|> anyHtmlInlineTag
   state <- getState
   if stateParseRaw state then return (HtmlInline result) else return (Str "")
 
 betweenTags tag = try $ htmlTag tag >> inlinesTilEnd tag >>= 
                         return . normalizeSpaces
 
-emph = (betweenTags "em" <|> betweenTags "it") >>= return . Emph
+emph = (betweenTags "em" <|> betweenTags "i") >>= return . Emph
 
 strong = (betweenTags "b" <|> betweenTags "strong") >>= return . Strong
 
diff --git a/Text/Pandoc/Readers/LaTeX.hs b/Text/Pandoc/Readers/LaTeX.hs
--- a/Text/Pandoc/Readers/LaTeX.hs
+++ b/Text/Pandoc/Readers/LaTeX.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Readers.LaTeX
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
@@ -374,7 +374,7 @@
   state <- getState
   if name == "item" && (stateParserContext state) == ListItemState
      then fail "should not be parsed as raw"
-     else string ""
+     else return ""
   if stateParseRaw state
      then return $ Plain [TeX ("\\" ++ name ++ star ++ argStr)]
      else return $ Plain [Str (joinWithSep " " args)]
@@ -648,5 +648,7 @@
   if ((name == "begin") || (name == "end") || (name == "item"))
      then fail "not an inline command" 
      else string ""
-  return $ TeX ("\\" ++ name ++ star ++ concat args)
+  if stateParseRaw state
+     then return $ TeX ("\\" ++ name ++ star ++ concat args)
+     else return $ Str (joinWithSep " " args)
 
diff --git a/Text/Pandoc/Readers/Markdown.hs b/Text/Pandoc/Readers/Markdown.hs
--- a/Text/Pandoc/Readers/Markdown.hs
+++ b/Text/Pandoc/Readers/Markdown.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Readers.Markdown
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
@@ -35,7 +35,6 @@
 import Data.Ord ( comparing )
 import Data.Char ( isAlphaNum )
 import Data.Maybe ( fromMaybe )
-import Network.URI ( isURI )
 import Text.Pandoc.Definition
 import Text.Pandoc.Shared 
 import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXEnvironment )
@@ -90,23 +89,20 @@
   state <- getState
   if stateSmart state then return () else fail "Smart typography feature"
 
--- | Parse an inline Str element with a given content.
-inlineString str = try $ do 
-  (Str res) <- inline 
-  if res == str then return res else fail $ "unexpected Str content"
-
--- | Parse a sequence of inline elements between a string
---  @opener@ and a string @closer@, including inlines
---  between balanced pairs of @opener@ and a @closer@.
-inlinesInBalanced :: String -> String -> GenParser Char ParserState [Inline]
-inlinesInBalanced opener closer = try $ do
-  string opener
-  result <- manyTill ( (do lookAhead (inlineString opener)
-                           -- because it might be a link...
-                           bal <- inlinesInBalanced opener closer 
-                           return $ [Str opener] ++ bal ++ [Str closer])
-                       <|> (count 1 inline)) 
-                     (try (string closer))
+-- | Parse a sequence of inline elements between square brackets,
+-- including inlines between balanced pairs of square brackets.
+inlinesInBalancedBrackets :: GenParser Char ParserState Inline
+                          -> GenParser Char ParserState [Inline]
+inlinesInBalancedBrackets parser = try $ do
+  char '['
+  result <- manyTill ( (do lookAhead $ try $ do (Str res) <- parser
+                                                if res == "["
+                                                   then return ()
+                                                   else pzero
+                           bal <- inlinesInBalancedBrackets parser
+                           return $ [Str "["] ++ bal ++ [Str "]"])
+                       <|> (count 1 parser))
+                     (char ']')
   return $ concat result
 
 --
@@ -230,17 +226,32 @@
 
 parseBlocks = manyTill block eof
 
-block = choice [ header 
-               , table
-               , codeBlock
-               , hrule
-               , list
-               , blockQuote
-               , htmlBlock
-               , rawLaTeXEnvironment'
-               , para
-               , plain
-               , nullBlock ] <?> "block"
+block = do
+  st <- getState
+  choice (if stateStrict st
+              then [ header
+                   , codeBlock
+                   , blockQuote
+                   , hrule
+                   , bulletList
+                   , orderedList
+                   , htmlBlock
+                   , para
+                   , plain
+                   , nullBlock ]
+              else [ header 
+                   , table
+                   , codeBlock
+                   , blockQuote
+                   , hrule
+                   , bulletList
+                   , orderedList
+                   , definitionList
+                   , rawLaTeXEnvironment
+                   , para
+                   , rawHtmlBlocks
+                   , plain
+                   , nullBlock ]) <?> "block"
 
 --
 -- header blocks
@@ -318,8 +329,6 @@
 -- list blocks
 --
 
-list = choice [ bulletList, orderedList, definitionList ] <?> "list"
-
 bulletListStart = try $ do
   optional newline -- if preceded by a Plain block in a list context
   nonindentSpaces
@@ -438,7 +447,6 @@
   return $ firstline ++ "\n" ++ unlines rawlines ++ trailing
 
 definitionList = do
-  failIfStrict
   items <- many1 definitionListItem
   let (terms, defs) = unzip items
   let defs' = compactify defs
@@ -449,8 +457,16 @@
 -- paragraph block
 --
 
+isHtmlOrBlank (HtmlInline _) = True
+isHtmlOrBlank (Space) = True
+isHtmlOrBlank (LineBreak) = True
+isHtmlOrBlank _ = False
+
 para = try $ do 
   result <- many1 inline
+  if all isHtmlOrBlank result
+     then fail "treat as raw HTML"
+     else return ()
   newline
   blanklines <|> do st <- getState
                     if stateStrict st
@@ -466,15 +482,12 @@
 
 htmlElement = strictHtmlBlock <|> htmlBlockElement <?> "html element"
 
-htmlBlock = do
-  st <- getState
-  if stateStrict st
-    then try $ do failUnlessBeginningOfLine
-                  first <- htmlElement
-                  finalSpace <- many (oneOf spaceChars)
-                  finalNewlines <- many newline
-                  return $ RawHtml $ first ++ finalSpace ++ finalNewlines
-    else rawHtmlBlocks
+htmlBlock = try $ do
+    failUnlessBeginningOfLine
+    first <- htmlElement
+    finalSpace <- many (oneOf spaceChars)
+    finalNewlines <- many newline
+    return $ RawHtml $ first ++ finalSpace ++ finalNewlines
 
 -- True if tag is self-closing
 isSelfClosing tag = 
@@ -491,20 +504,21 @@
              return $ tag ++ concat contents ++ end
 
 rawHtmlBlocks = do
-  htmlBlocks <- many1 rawHtmlBlock    
-  let combined = concatMap (\(RawHtml str) -> str) htmlBlocks
-  let combined' = if not (null combined) && last combined == '\n'
-                     then init combined  -- strip extra newline 
-                     else combined 
+  htmlBlocks <- many1 $ do (RawHtml blk) <- rawHtmlBlock
+                           sps <- do sp1 <- many spaceChar
+                                     sp2 <- option "" (blankline >> return "\n")
+                                     sp3 <- many spaceChar
+                                     sp4 <- option "" blanklines
+                                     return $ sp1 ++ sp2 ++ sp3 ++ sp4
+                           -- note: we want raw html to be able to
+                           -- precede a code block, when separated
+                           -- by a blank line
+                           return $ blk ++ sps
+  let combined = concat htmlBlocks
+  let combined' = if last combined == '\n' then init combined else combined
   return $ RawHtml combined'
 
 --
--- LaTeX
---
-
-rawLaTeXEnvironment' = failIfStrict >> rawLaTeXEnvironment
-
---
 -- Tables
 -- 
 
@@ -625,13 +639,15 @@
         (True,  True)    -> AlignCenter
         (False, False)   -> AlignDefault
 
-table = failIfStrict >> (simpleTable <|> multilineTable) <?> "table"
+table = simpleTable <|> multilineTable <?> "table"
 
 -- 
 -- inline
 --
 
-inline = choice [ str
+inline = choice inlineParsers <?> "inline"
+
+inlineParsers = [ str
                 , smartPunctuation
                 , whitespace
                 , endline
@@ -652,8 +668,15 @@
                 , rawLaTeXInline'
                 , escapedChar
                 , symbol
-                , ltSign ] <?> "inline"
+                , ltSign ]
 
+inlineNonLink = (choice $
+                 map (\parser -> try (parser >>= failIfLink)) inlineParsers)
+                <?> "inline (non-link)"
+
+failIfLink (Link _ _) = pzero
+failIfLink elt = return elt
+
 escapedChar = do
   char '\\'
   state <- getState
@@ -696,8 +719,9 @@
   char '$'
   return $ Math $ joinWithSep " " words
 
-emph = ((enclosed (char '*') (char '*') inline) <|>
-        (enclosed (char '_') (char '_' >> notFollowedBy alphaNum) inline)) >>= 
+emph = ((enclosed (char '*') (notFollowedBy' strong >> char '*') inline) <|>
+        (enclosed (char '_') (notFollowedBy' strong >> char '_' >> 
+                              notFollowedBy alphaNum) inline)) >>= 
         return . Emph . normalizeSpaces
 
 strong = ((enclosed (string "**") (try $ string "**") inline) <|> 
@@ -813,26 +837,35 @@
 --
 
 -- a reference label for a link
-reference = notFollowedBy' (string "[^") >>  -- footnote reference
-            inlinesInBalanced "[" "]" >>= (return . normalizeSpaces)
+reference = do notFollowedBy' (string "[^")   -- footnote reference
+               result <- inlinesInBalancedBrackets inlineNonLink
+               return $ normalizeSpaces result
 
 -- source for a link, with optional title
-source = try $ do 
-  char '('
-  optional (char '<')
-  src <- many (noneOf ")> \t\n")
-  optional (char '>')
+source =
+  (try $ charsInBalanced '(' ')' >>= parseFromString source') <|>
+  -- the following is needed for cases like:  [ref](/url(a).
+  (enclosed (char '(') (char ')') anyChar >>=
+   parseFromString source')
+
+-- auxiliary function for source
+source' = do
+  skipSpaces
+  src <- try (char '<' >>
+              many (optional (char '\\') >> noneOf "> \t\n") >>~
+              char '>')
+         <|> many (optional (char '\\') >> noneOf " \t\n")
   tit <- option "" linkTitle
   skipSpaces
-  char ')'
+  eof
   return (removeTrailingSpace src, tit)
 
 linkTitle = try $ do 
   (many1 spaceChar >> option '\n' newline) <|> newline
   skipSpaces
-  delim <- char '\'' <|> char '"'
-  tit <-   manyTill anyChar (try (char delim >> skipSpaces >>
-                                  notFollowedBy (noneOf ")\n")))
+  delim <- oneOf "'\""
+  tit <-   manyTill (optional (char '\\') >> anyChar)
+                    (try (char delim >> skipSpaces >> eof))
   return $ decodeCharacterReferences tit
 
 link = try $ do
@@ -850,22 +883,9 @@
      Nothing     -> fail "no corresponding key" 
      Just target -> return target 
 
-emailAddress = try $ do
-  name <- many1 (alphaNum <|> char '+')
-  char '@'
-  first <- many1 alphaNum
-  rest <- many1 (char '.' >> many1 alphaNum)
-  return $ "mailto:" ++ name ++ "@" ++ joinWithSep "." (first:rest)
-
-uri = try $ do
-  str <- many1 (noneOf "\n\t >")
-  if isURI str
-     then return str
-     else fail "not a URI"
-
 autoLink = try $ do
   char '<'
-  src <- uri <|> emailAddress
+  src <- uri <|> (emailAddress >>= (return . ("mailto:" ++)))
   char '>'
   let src' = if "mailto:" `isPrefixOf` src
                 then drop 7 src
@@ -892,15 +912,15 @@
 inlineNote = try $ do
   failIfStrict
   char '^'
-  contents <- inlinesInBalanced "[" "]"
+  contents <- inlinesInBalancedBrackets inline
   return $ Note [Para contents]
 
 rawLaTeXInline' = failIfStrict >> rawLaTeXInline
 
 rawHtmlInline' = do
   st <- getState
-  result <- choice $ if stateStrict st
-                        then [htmlBlockElement, anyHtmlTag, anyHtmlEndTag] 
-                        else [htmlBlockElement, anyHtmlInlineTag]
+  result <- if stateStrict st
+               then choice [htmlBlockElement, anyHtmlTag, anyHtmlEndTag] 
+               else anyHtmlInlineTag
   return $ HtmlInline result
 
diff --git a/Text/Pandoc/Readers/RST.hs b/Text/Pandoc/Readers/RST.hs
--- a/Text/Pandoc/Readers/RST.hs
+++ b/Text/Pandoc/Readers/RST.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Readers.RST 
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
@@ -433,9 +433,29 @@
 -- reference key
 --
 
+quotedReferenceName = try $ do
+  char '`' >> notFollowedBy (char '`') -- `` means inline code!
+  label <- many1Till inline (char '`') 
+  return label
+
+unquotedReferenceName = try $ do
+  label <- many1Till inline (lookAhead $ char ':')
+  return label
+
+isolated ch = try $ char ch >>~ notFollowedBy (char ch)
+
+simpleReferenceName = do
+  raw <- many1 (alphaNum <|> isolated '-' <|> isolated '.' <|>
+                (try $ char '_' >>~ lookAhead alphaNum))
+  return [Str raw]
+
+referenceName = quotedReferenceName <|>
+                (try $ simpleReferenceName >>~ lookAhead (char ':')) <|>
+                unquotedReferenceName
+
 referenceKey = do
   startPos <- getPosition
-  key <- choice [imageKey, anonymousKey, regularKeyQuoted, regularKey]
+  key <- choice [imageKey, anonymousKey, regularKey]
   st <- getState
   let oldkeys = stateKeys st
   updateState $ \st -> st { stateKeys = key : oldkeys }
@@ -466,16 +486,10 @@
   state <- getState
   return ([Str "_"], (removeLeadingTrailingSpace src, ""))
 
-regularKeyQuoted = try $ do
-  string ".. _`"
-  ref <- manyTill inline (char '`')
-  char ':'
-  src <- targetURI
-  return (normalizeSpaces ref, (removeLeadingTrailingSpace src, ""))
-
 regularKey = try $ do
   string ".. _"
-  ref <- manyTill inline (char ':')
+  ref <- referenceName
+  char ':'
   src <- targetURI
   return (normalizeSpaces ref, (removeLeadingTrailingSpace src, ""))
 
@@ -534,8 +548,7 @@
 
 whitespace = many1 spaceChar >> return Space <?> "whitespace"
 
-str = notFollowedBy' oneWordReference >> 
-      many1 (noneOf (specialChars ++ "\t\n ")) >>= return . Str
+str = many1 (noneOf (specialChars ++ "\t\n ")) >>= return . Str
 
 -- an endline character that can be treated as a space, not a structural break
 endline = try $ do
@@ -557,28 +570,16 @@
 
 explicitLink = try $ do
   char '`'
-  notFollowedBy (char '`') -- `` is marks start of inline code
-  label <- manyTill inline (try (do {spaces; char '<'}))
+  notFollowedBy (char '`') -- `` marks start of inline code
+  label <- manyTill (notFollowedBy (char '`') >> inline) 
+                    (try (spaces >> char '<'))
   src <- manyTill (noneOf ">\n ") (char '>')
   skipSpaces
   string "`_"
   return $ Link (normalizeSpaces label) (removeLeadingTrailingSpace src, "")
 
-reference = try $ do
-  char '`'
-  notFollowedBy (char '`')
-  label <- many1Till inline (char '`') 
-  char '_'
-  return label
-
-oneWordReference = do
-  raw <- many1 alphaNum
-  char '_'
-  notFollowedBy alphaNum    -- because this_is_not a link
-  return [Str raw]
-
 referenceLink = try $ do
-  label <- reference <|> oneWordReference
+  label <- (quotedReferenceName <|> simpleReferenceName) >>~ char '_'
   key <- option label (do{char '_'; return [Str "_"]}) -- anonymous link
   state <- getState
   let keyTable = stateKeys state
@@ -592,34 +593,9 @@
   setState $ state { stateKeys = keyTable' }
   return $ Link (normalizeSpaces label) src 
 
-uriScheme = oneOfStrings [ "http://", "https://", "ftp://", "file://", 
-                           "mailto:", "news:", "telnet:" ]
-
-uri = try $ do
-  scheme <- uriScheme
-  identifier <- many1 (noneOf " \t\n")
-  return $ scheme ++ identifier
-
 autoURI = do
   src <- uri
   return $ Link [Str src] (src, "")
-
-emailChar = alphaNum <|> oneOf "-+_."
-
-emailAddress = try $ do
-  firstLetter <- alphaNum
-  restAddr <- many emailChar
-  let addr = firstLetter:restAddr
-  char '@'
-  dom <- domain
-  return $ addr ++ '@':dom
-
-domainChar = alphaNum <|> char '-'
-
-domain = do
-  first <- many1 domainChar
-  dom <- many1 (try (do{ char '.'; many1 domainChar }))
-  return $ joinWithSep "." (first:dom)
 
 autoEmail = do
   src <- emailAddress
diff --git a/Text/Pandoc/Shared.hs b/Text/Pandoc/Shared.hs
--- a/Text/Pandoc/Shared.hs
+++ b/Text/Pandoc/Shared.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Shared
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
@@ -64,6 +64,8 @@
                      charsInBalanced,
                      charsInBalanced',
                      romanNumeral,
+                     emailAddress,
+                     uri,
                      withHorizDisplacement,
                      nullBlock,
                      failIfStrict,
@@ -105,6 +107,7 @@
 import Data.Char ( toLower, toUpper, ord, isLower, isUpper )
 import Data.List ( find, isPrefixOf )
 import Control.Monad ( join )
+import Network.URI ( parseURI, URI (..), isAllowedInURI )
 
 --
 -- List processing
@@ -404,6 +407,38 @@
        then fail "not a roman numeral"
        else return total
 
+-- Parsers for email addresses and URIs
+
+emailChar = alphaNum <|> oneOf "-+_."
+
+domainChar = alphaNum <|> char '-'
+
+domain = do
+  first <- many1 domainChar
+  dom <- many1 (try (do{ char '.'; many1 domainChar }))
+  return $ joinWithSep "." (first:dom)
+
+-- | Parses an email address; returns string.
+emailAddress :: GenParser Char st [Char]
+emailAddress = try $ do
+  firstLetter <- alphaNum
+  restAddr <- many emailChar
+  let addr = firstLetter:restAddr
+  char '@'
+  dom <- domain
+  return $ addr ++ '@':dom
+
+-- | Parses a URI.
+uri = try $ do
+  str <- many1 $ satisfy isAllowedInURI
+  case parseURI str of
+       Just uri' -> if uriScheme uri' `elem` [ "http:", "https:", "ftp:",
+                                               "file:", "mailto:",
+                                               "news:", "telnet:" ]
+                       then return $ show uri'
+                       else fail "not a URI"
+       Nothing   -> fail "not a URI"
+
 -- | Applies a parser, returns tuple of its results and its horizontal
 -- displacement (the difference between the source column at the end
 -- and the source column at the beginning). Vertical displacement
@@ -560,6 +595,7 @@
     { stateParseRaw        :: Bool,          -- ^ Parse raw HTML and LaTeX?
       stateParserContext   :: ParserContext, -- ^ Inside list?
       stateQuoteContext    :: QuoteContext,  -- ^ Inside quoted environment?
+      stateSanitizeHTML    :: Bool,          -- ^ Sanitize HTML?
       stateKeys            :: KeyTable,      -- ^ List of reference keys
       stateNotes           :: NoteTable,     -- ^ List of notes
       stateTabStop         :: Int,           -- ^ Tab stop
@@ -579,6 +615,7 @@
     ParserState { stateParseRaw        = False,
                   stateParserContext   = NullState,
                   stateQuoteContext    = NoQuote,
+                  stateSanitizeHTML    = False,
                   stateKeys            = [],
                   stateNotes           = [],
                   stateTabStop         = 4,
diff --git a/Text/Pandoc/Writers/ConTeXt.hs b/Text/Pandoc/Writers/ConTeXt.hs
--- a/Text/Pandoc/Writers/ConTeXt.hs
+++ b/Text/Pandoc/Writers/ConTeXt.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2007 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Writers.ConTeXt
-   Copyright   : Copyright (C) 2007 John MacFarlane
+   Copyright   : Copyright (C) 2007-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
@@ -41,6 +41,8 @@
               , stOptions          :: WriterOptions -- writer options
               }
 
+data BlockWrapper = Pad Doc | Reg Doc 
+
 orderedListStyles = cycle ["[n]","[a]", "[r]", "[g]"] 
 
 -- | Convert Pandoc to ConTeXt.
@@ -123,28 +125,28 @@
 
 -- | Convert Pandoc block element to ConTeXt.
 blockToConTeXt :: Block 
-               -> State WriterState Doc 
-blockToConTeXt Null = return empty
+               -> State WriterState BlockWrapper
+blockToConTeXt Null = return $ Reg empty
 blockToConTeXt (Plain lst) = do
   st <- get
   let options = stOptions st
   contents <- wrapTeXIfNeeded options False inlineListToConTeXt lst 
-  return contents
+  return $ Reg contents
 blockToConTeXt (Para lst) = do 
   st <- get
   let options = stOptions st
   contents <- wrapTeXIfNeeded options False inlineListToConTeXt lst
-  return $ contents <> char '\n'
+  return $ Pad contents
 blockToConTeXt (BlockQuote lst) = do
   contents <- blockListToConTeXt lst
-  return $ text "\\startblockquote\n" $$ contents $$ text "\\stopblockquote"
+  return $ Pad $ text "\\startblockquote" $$ contents $$ text "\\stopblockquote"
 blockToConTeXt (CodeBlock str) = 
-  return $ text $ "\\starttyping\n" ++ str ++ "\n\\stoptyping\n" -- \n needed
-  -- because \stoptyping can't have anything after it
-blockToConTeXt (RawHtml str) = return empty
+  return $ Reg $ text $ "\\starttyping\n" ++ str ++ "\n\\stoptyping\n" 
+  -- \n because \stoptyping can't have anything after it, inc. }
+blockToConTeXt (RawHtml str) = return $ Reg empty
 blockToConTeXt (BulletList lst) = do 
   contents <- mapM listItemToConTeXt lst
-  return $ text "\\startitemize" $$ vcat contents $$ text "\\stopitemize\n"
+  return $ Pad $ text "\\startitemize" $$ vcat contents $$ text "\\stopitemize"
 blockToConTeXt (OrderedList (start, style, delim) lst) = do
     st <- get
     let level = stOrderedListLevel st
@@ -175,20 +177,20 @@
                         LowerAlpha   -> "[a]"
                         UpperAlpha   -> "[A]"
     let specs = style' ++ specs2
-    return $ text ("\\startitemize" ++ specs) $$ vcat contents $$ 
-             text "\\stopitemize\n"
+    return $ Pad $ text ("\\startitemize" ++ specs) $$ vcat contents $$ 
+             text "\\stopitemize"
 blockToConTeXt (DefinitionList lst) =
-  mapM defListItemToConTeXt lst >>= return . (<> char '\n') . vcat
-blockToConTeXt HorizontalRule = return $ text "\\thinrule\n"
+  mapM defListItemToConTeXt lst >>= return . Pad . wrappedBlocksToDoc
+blockToConTeXt HorizontalRule = return $ Pad $ text "\\thinrule"
 blockToConTeXt (Header level lst) = do
   contents <- inlineListToConTeXt lst
   st <- get
   let opts = stOptions st
   let base = if writerNumberSections opts then "section" else "subject"
-  return $ if level >= 1 && level <= 5
-              then char '\\' <> text (concat (replicate (level - 1) "sub")) <> 
-                   text base <> char '{' <> contents <> char '}' <> char '\n'
-              else contents <> char '\n'
+  return $ Pad $ if level >= 1 && level <= 5
+                    then char '\\' <> text (concat (replicate (level - 1) "sub")) <> 
+                         text base <> char '{' <> contents <> char '}'
+                    else contents
 blockToConTeXt (Table caption aligns widths heads rows) = do
     let colWidths = map printDecimal widths
     let colDescriptor colWidth alignment = (case alignment of
@@ -203,10 +205,10 @@
     captionText <- inlineListToConTeXt caption 
     let captionText' = if null caption then text "none" else captionText
     rows' <- mapM tableRowToConTeXt rows 
-    return $ text "\\placetable[here]{" <> captionText' <> char '}' $$
+    return $ Pad $ text "\\placetable[here]{" <> captionText' <> char '}' $$
              text "\\starttable[" <> text colDescriptors <> char ']' $$
              text "\\HL" $$ headers $$ text "\\HL" $$
-             vcat rows' $$ text "\\HL\n\\stoptable\n" 
+             vcat rows' $$ text "\\HL\n\\stoptable"
 
 printDecimal :: Float -> String
 printDecimal = printf "%.2f" 
@@ -225,11 +227,17 @@
 defListItemToConTeXt (term, def) = do
   term' <- inlineListToConTeXt term
   def'  <- blockListToConTeXt def
-  return $ text "\\startdescr{" <> term' <> char '}' $$ def' $$ text "\\stopdescr"
+  return $ Pad $ text "\\startdescr{" <> term' <> char '}' $$ def' $$ text "\\stopdescr"
 
+wrappedBlocksToDoc :: [BlockWrapper] -> Doc
+wrappedBlocksToDoc = foldr addBlock empty 
+     where addBlock (Pad d) accum | isEmpty accum = d
+           addBlock (Pad d) accum = d $$ text "" $$ accum
+           addBlock (Reg d) accum = d $$ accum
+
 -- | Convert list of block elements to ConTeXt.
 blockListToConTeXt :: [Block] -> State WriterState Doc
-blockListToConTeXt lst = mapM blockToConTeXt lst >>= return . vcat
+blockListToConTeXt lst = mapM blockToConTeXt lst >>= return . wrappedBlocksToDoc
 
 -- | Convert list of inline elements to ConTeXt.
 inlineListToConTeXt :: [Inline]  -- ^ Inlines to convert
diff --git a/Text/Pandoc/Writers/HTML.hs b/Text/Pandoc/Writers/HTML.hs
--- a/Text/Pandoc/Writers/HTML.hs
+++ b/Text/Pandoc/Writers/HTML.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Writers.HTML 
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
@@ -35,7 +35,7 @@
 import Text.Pandoc.Readers.TeXMath
 import Text.Regex ( mkRegex, matchRegex )
 import Numeric ( showHex )
-import Data.Char ( ord, toLower )
+import Data.Char ( ord, toLower, isAlpha )
 import Data.List ( isPrefixOf, intersperse )
 import qualified Data.Set as S
 import Control.Monad.State
@@ -71,8 +71,10 @@
   let titlePrefix = writerTitlePrefix opts
       topTitle    = evalState (inlineListToHtml opts tit) defaultWriterState
       topTitle'   = if null titlePrefix
-                        then topTitle
-                        else titlePrefix +++ " - " +++ topTitle
+                       then topTitle
+                       else if null tit 
+                               then stringToHtml titlePrefix
+                               else titlePrefix +++ " - " +++ topTitle
       metadata    = thetitle topTitle' +++ 
                     meta ! [httpequiv "Content-Type", 
                             content "text/html; charset=UTF-8"] +++
@@ -215,18 +217,20 @@
 
 -- | Convert Pandoc inline list to plain text identifier.
 inlineListToIdentifier :: [Inline] -> String
-inlineListToIdentifier [] = ""
-inlineListToIdentifier (x:xs) = 
-  xAsText ++ inlineListToIdentifier xs
+inlineListToIdentifier = dropWhile (not . isAlpha) . inlineListToIdentifier'
+
+inlineListToIdentifier' [] = ""
+inlineListToIdentifier' (x:xs) = 
+  xAsText ++ inlineListToIdentifier' xs
   where xAsText = case x of
           Str s          -> filter (\c -> c == '-' || not (isPunctuation c)) $
                             concat $ intersperse "-" $ words $ map toLower s
-          Emph lst       -> inlineListToIdentifier lst
-          Strikeout lst  -> inlineListToIdentifier lst
-          Superscript lst -> inlineListToIdentifier lst
-          Subscript lst  -> inlineListToIdentifier lst
-          Strong lst     -> inlineListToIdentifier lst
-          Quoted _ lst   -> inlineListToIdentifier lst
+          Emph lst       -> inlineListToIdentifier' lst
+          Strikeout lst  -> inlineListToIdentifier' lst
+          Superscript lst -> inlineListToIdentifier' lst
+          Subscript lst  -> inlineListToIdentifier' lst
+          Strong lst     -> inlineListToIdentifier' lst
+          Quoted _ lst   -> inlineListToIdentifier' lst
           Code s         -> s
           Space          -> "-"
           EmDash         -> "-"
@@ -237,8 +241,8 @@
           Math _         -> ""
           TeX _          -> ""
           HtmlInline _   -> ""
-          Link lst _     -> inlineListToIdentifier lst
-          Image lst _    -> inlineListToIdentifier lst
+          Link lst _     -> inlineListToIdentifier' lst
+          Image lst _    -> inlineListToIdentifier' lst
           Note _         -> ""
 
 -- | Return unique identifiers for list of inline lists.
@@ -247,7 +251,8 @@
   let addIdentifier (nonuniqueIds, uniqueIds) l =
         let new = inlineListToIdentifier l
             matches = length $ filter (== new) nonuniqueIds
-            new' = new ++ if matches > 0 then ("-" ++ show matches) else ""
+            new' = (if null new then "section" else new) ++ 
+                   if matches > 0 then ("-" ++ show matches) else ""
         in  (new:nonuniqueIds, new':uniqueIds)
   in  reverse $ snd $ foldl addIdentifier ([],[]) ls
 
diff --git a/Text/Pandoc/Writers/LaTeX.hs b/Text/Pandoc/Writers/LaTeX.hs
--- a/Text/Pandoc/Writers/LaTeX.hs
+++ b/Text/Pandoc/Writers/LaTeX.hs
@@ -1,5 +1,5 @@
 {-
-Copyright (C) 2006-7 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-8 John MacFarlane <jgm@berkeley.edu>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 {- |
    Module      : Text.Pandoc.Writers.LaTeX
-   Copyright   : Copyright (C) 2006-7 John MacFarlane
+   Copyright   : Copyright (C) 2006-8 John MacFarlane
    License     : GNU GPL, version 2 or above 
 
    Maintainer  : John MacFarlane <jgm@berkeley.edu>
diff --git a/Text/Pandoc/Writers/RST.hs b/Text/Pandoc/Writers/RST.hs
--- a/Text/Pandoc/Writers/RST.hs
+++ b/Text/Pandoc/Writers/RST.hs
@@ -40,16 +40,26 @@
 
 type Notes = [[Block]]
 type Refs = KeyTable
-type WriterState = (Notes, Refs, Refs) -- first Refs is links, second pictures
+data WriterState = 
+  WriterState { stNotes     :: [[Block]]
+              , stLinks     :: KeyTable
+              , stImages    :: KeyTable
+              , stIncludes  :: [String]
+              , stOptions   :: WriterOptions
+              }
 
 -- | Convert Pandoc to RST.
 writeRST :: WriterOptions -> Pandoc -> String
 writeRST opts document = 
-  render $ evalState (pandocToRST opts document) ([],[],[]) 
+  let st = WriterState { stNotes = [], stLinks = [],
+                         stImages = [], stIncludes = [],
+                         stOptions = opts }
+  in render $ evalState (pandocToRST document) st
 
 -- | Return RST representation of document.
-pandocToRST :: WriterOptions -> Pandoc -> State WriterState Doc
-pandocToRST opts (Pandoc meta blocks) = do
+pandocToRST :: Pandoc -> State WriterState Doc
+pandocToRST (Pandoc meta blocks) = do
+  opts <- get >>= (return . stOptions)
   let before  = writerIncludeBefore opts
   let after   = writerIncludeAfter opts
       before' = if null before then empty else text before
@@ -58,60 +68,62 @@
   let head = if (writerStandalone opts)
                 then metaBlock $+$ text (writerHeader opts)
                 else empty
-  body <- blockListToRST opts blocks
-  (notes, _, _) <- get
-  notes' <- notesToRST opts (reverse notes)
-  (_, refs, pics) <- get  -- note that the notes may contain refs
-  refs' <- keyTableToRST opts (reverse refs)
-  pics' <- pictTableToRST opts (reverse pics)
-  return $ head $+$ before' $+$ body $+$ notes' $+$ text "" $+$ refs' $+$ 
-           pics' $+$ after'
+  body <- blockListToRST blocks
+  includes <- get >>= (return . concat . stIncludes)
+  let includes' = if null includes then empty else text includes
+  notes <- get >>= (notesToRST . reverse . stNotes)
+  -- note that the notes may contain refs, so we do them first
+  refs <- get >>= (keyTableToRST . reverse . stLinks)
+  pics <- get >>= (pictTableToRST . reverse . stImages)
+  return $ head $+$ before' $+$ includes' $+$ body $+$ notes $+$ text "" $+$
+           refs $+$ pics $+$ after'
 
 -- | Return RST representation of reference key table.
-keyTableToRST :: WriterOptions -> KeyTable -> State WriterState Doc
-keyTableToRST opts refs = mapM (keyToRST opts) refs >>= return . vcat
+keyTableToRST :: KeyTable -> State WriterState Doc
+keyTableToRST refs = mapM keyToRST refs >>= return . vcat
  
 -- | Return RST representation of a reference key. 
-keyToRST :: WriterOptions 
-         -> ([Inline], (String, String)) 
+keyToRST :: ([Inline], (String, String)) 
          -> State WriterState Doc
-keyToRST opts (label, (src, tit)) = do
-  label' <- inlineListToRST opts label
+keyToRST (label, (src, tit)) = do
+  label' <- inlineListToRST label
   let label'' = if ':' `elem` (render label')
                    then char '`' <> label' <> char '`'
                    else label'
   return $ text ".. _" <> label'' <> text ": " <> text src
 
 -- | Return RST representation of notes.
-notesToRST :: WriterOptions -> [[Block]] -> State WriterState Doc
-notesToRST opts notes = 
-  mapM (\(num, note) -> noteToRST opts num note) (zip [1..] notes) >>= 
+notesToRST :: [[Block]] -> State WriterState Doc
+notesToRST notes = 
+  mapM (\(num, note) -> noteToRST num note) (zip [1..] notes) >>= 
   return . vcat
 
 -- | Return RST representation of a note.
-noteToRST :: WriterOptions -> Int -> [Block] -> State WriterState Doc
-noteToRST opts num note = do
-  contents <- blockListToRST opts note
+noteToRST :: Int -> [Block] -> State WriterState Doc
+noteToRST num note = do
+  contents <- blockListToRST note
   let marker = text ".. [" <> text (show num) <> text "] "
   return $ hang marker 3 contents 
 
 -- | Return RST representation of picture reference table.
-pictTableToRST :: WriterOptions -> KeyTable -> State WriterState Doc
-pictTableToRST opts refs = mapM (pictToRST opts) refs >>= return . vcat
+pictTableToRST :: KeyTable -> State WriterState Doc
+pictTableToRST refs = mapM pictToRST refs >>= return . vcat
  
 -- | Return RST representation of a picture substitution reference. 
-pictToRST :: WriterOptions 
-         -> ([Inline], (String, String)) 
-         -> State WriterState Doc
-pictToRST opts (label, (src, _)) = do
-  label' <- inlineListToRST opts label
+pictToRST :: ([Inline], (String, String)) 
+          -> State WriterState Doc
+pictToRST (label, (src, _)) = do
+  label' <- inlineListToRST label
   return $ text ".. " <> char '|' <> label' <> char '|' <> text " image:: " <>
            text src
 
 -- | Take list of inline elements and return wrapped doc.
 wrappedRST :: WriterOptions -> [Inline] -> State WriterState Doc
-wrappedRST opts inlines = mapM (wrapIfNeeded opts (inlineListToRST opts))
-                          (splitBy LineBreak inlines) >>= return . vcat
+wrappedRST opts inlines = do
+  lineBreakDoc <- inlineToRST LineBreak  
+  chunks <- mapM (wrapIfNeeded opts inlineListToRST)
+                 (splitBy LineBreak inlines)
+  return $ vcat $ intersperse lineBreakDoc chunks
 
 -- | Escape special characters for RST.
 escapeString :: String -> String
@@ -120,7 +132,7 @@
 -- | Convert bibliographic information into RST header.
 metaToRST :: WriterOptions -> Meta -> State WriterState Doc
 metaToRST opts (Meta title authors date) = do
-  title'   <- titleToRST opts title
+  title'   <- titleToRST title
   authors' <- authorsToRST authors
   date'    <- dateToRST date
   let toc  =  if writerTableOfContents opts
@@ -128,10 +140,10 @@
                  else empty
   return $ title' $+$ authors' $+$ date' $+$ toc
 
-titleToRST :: WriterOptions -> [Inline] -> State WriterState Doc
-titleToRST opts [] = return empty
-titleToRST opts lst = do
-  contents <- inlineListToRST opts lst
+titleToRST :: [Inline] -> State WriterState Doc
+titleToRST [] = return empty
+titleToRST lst = do
+  contents <- inlineListToRST lst
   let titleLength = length $ render contents
   let border = text (replicate titleLength '=')
   return $ border $+$ contents $+$ border <> text "\n"
@@ -147,35 +159,40 @@
 dateToRST str = return $ text ":Date: " <> text (escapeString str)
 
 -- | Convert Pandoc block element to RST. 
-blockToRST :: WriterOptions -- ^ Options
-                -> Block         -- ^ Block element
-                -> State WriterState Doc 
-blockToRST opts Null = return empty
-blockToRST opts (Plain inlines) = wrappedRST opts inlines
-blockToRST opts (Para inlines) = do
+blockToRST :: Block         -- ^ Block element
+           -> State WriterState Doc 
+blockToRST Null = return empty
+blockToRST (Plain inlines) = do
+  opts <- get >>= (return . stOptions)
+  wrappedRST opts inlines
+blockToRST (Para inlines) = do
+  opts <- get >>= (return . stOptions)
   contents <- wrappedRST opts inlines
   return $ contents <> text "\n"
-blockToRST opts (RawHtml str) = 
+blockToRST (RawHtml str) = 
   let str' = if "\n" `isSuffixOf` str then str ++ "\n" else str ++ "\n\n" in
   return $ hang (text "\n.. raw:: html\n") 3 $ vcat $ map text (lines str')
-blockToRST opts HorizontalRule = return $ text "--------------\n"
-blockToRST opts (Header level inlines) = do
-  contents <- inlineListToRST opts inlines
+blockToRST HorizontalRule = return $ text "--------------\n"
+blockToRST (Header level inlines) = do
+  contents <- inlineListToRST inlines
   let headerLength = length $ render contents
   let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
   let border = text $ replicate headerLength headerChar
   return $ contents $+$ border <> text "\n"
-blockToRST opts (CodeBlock str) = return $ (text "::\n") $+$ 
-  (nest (writerTabStop opts) $ vcat $ map text (lines str)) <> text "\n"
-blockToRST opts (BlockQuote blocks) = do
-  contents <- blockListToRST opts blocks 
-  return $ (nest (writerTabStop opts) contents) <> text "\n"
-blockToRST opts (Table caption aligns widths headers rows) =  do
-  caption' <- inlineListToRST opts caption
+blockToRST (CodeBlock str) = do
+  tabstop <- get >>= (return . writerTabStop . stOptions)
+  return $ (text "::\n") $+$ 
+            (nest tabstop $ vcat $ map text (lines str)) <> text "\n"
+blockToRST (BlockQuote blocks) = do
+  tabstop <- get >>= (return . writerTabStop . stOptions)
+  contents <- blockListToRST blocks 
+  return $ (nest tabstop contents) <> text "\n"
+blockToRST (Table caption aligns widths headers rows) =  do
+  caption' <- inlineListToRST caption
   let caption'' = if null caption
                      then empty
                      else text "" $+$ (text "Table: " <> caption')
-  headers' <- mapM (blockListToRST opts) headers
+  headers' <- mapM blockListToRST headers
   let widthsInChars = map (floor . (78 *)) widths
   let alignHeader alignment = case alignment of
                                 AlignLeft    -> leftAlignBlock
@@ -190,7 +207,7 @@
               middle = hcatBlocks $ intersperse sep blocks
   let makeRow = hpipeBlocks . zipWith docToBlock widthsInChars
   let head = makeRow headers'
-  rows' <- mapM (\row -> do cols <- mapM (blockListToRST opts) row
+  rows' <- mapM (\row -> do cols <- mapM blockListToRST row
                             return $ makeRow cols) rows
   let tableWidth = sum widthsInChars
   let maxRowHeight = maximum $ map heightOfBlock (head:rows')
@@ -201,11 +218,11 @@
   let body = vcat $ intersperse (border '-') $ map blockToDoc rows'
   return $ border '-' $+$ blockToDoc head $+$ border '=' $+$ body $+$ 
            border '-' $$ caption'' $$ text ""
-blockToRST opts (BulletList items) = do
-  contents <- mapM (bulletListItemToRST opts) items
+blockToRST (BulletList items) = do
+  contents <- mapM bulletListItemToRST items
   -- ensure that sublists have preceding blank line
   return $ text "" $+$ vcat contents <> text "\n"
-blockToRST opts (OrderedList (start, style, delim) items) = do
+blockToRST (OrderedList (start, style, delim) items) = do
   let markers = if start == 1 && style == DefaultStyle && delim == DefaultDelim 
                    then take (length items) $ repeat "#."
                    else take (length items) $ orderedListMarkers 
@@ -213,112 +230,118 @@
   let maxMarkerLength = maximum $ map length markers
   let markers' = map (\m -> let s = maxMarkerLength - length m
                             in  m ++ replicate s ' ') markers
-  contents <- mapM (\(item, num) -> orderedListItemToRST opts item num) $
+  contents <- mapM (\(item, num) -> orderedListItemToRST item num) $
               zip markers' items  
   -- ensure that sublists have preceding blank line
   return $ text "" $+$ vcat contents <> text "\n"
-blockToRST opts (DefinitionList items) = do
-  contents <- mapM (definitionListItemToRST opts) items
+blockToRST (DefinitionList items) = do
+  contents <- mapM definitionListItemToRST items
   return $ (vcat contents) <> text "\n"
 
 -- | Convert bullet list item (list of blocks) to RST.
-bulletListItemToRST :: WriterOptions -> [Block] -> State WriterState Doc
-bulletListItemToRST opts items = do
-  contents <- blockListToRST opts items
+bulletListItemToRST :: [Block] -> State WriterState Doc
+bulletListItemToRST items = do
+  contents <- blockListToRST items
   return $ hang (text "- ") 3 contents
 
 -- | Convert ordered list item (a list of blocks) to RST.
-orderedListItemToRST :: WriterOptions -- ^ options
-                          -> String   -- ^ marker for list item
-                          -> [Block]  -- ^ list item (list of blocks)
-                          -> State WriterState Doc
-orderedListItemToRST opts marker items = do
-  contents <- blockListToRST opts items
+orderedListItemToRST :: String   -- ^ marker for list item
+                     -> [Block]  -- ^ list item (list of blocks)
+                     -> State WriterState Doc
+orderedListItemToRST marker items = do
+  contents <- blockListToRST items
   return $ hang (text marker) (length marker + 1) contents 
 
 -- | Convert defintion list item (label, list of blocks) to RST.
-definitionListItemToRST :: WriterOptions -> ([Inline], [Block]) -> State WriterState Doc
-definitionListItemToRST opts (label, items) = do
-  label <- inlineListToRST opts label
-  contents <- blockListToRST opts items
-  return $ label $+$ nest (writerTabStop opts) contents
+definitionListItemToRST :: ([Inline], [Block]) -> State WriterState Doc
+definitionListItemToRST (label, items) = do
+  label <- inlineListToRST label
+  contents <- blockListToRST items
+  tabstop <- get >>= (return . writerTabStop . stOptions)
+  return $ label $+$ nest tabstop contents
 
 -- | Convert list of Pandoc block elements to RST.
-blockListToRST :: WriterOptions -- ^ Options
-                    -> [Block]       -- ^ List of block elements
-                    -> State WriterState Doc 
-blockListToRST opts blocks =
-  mapM (blockToRST opts) blocks >>= return . vcat
+blockListToRST :: [Block]       -- ^ List of block elements
+               -> State WriterState Doc 
+blockListToRST blocks = mapM blockToRST blocks >>= return . vcat
 
 -- | Convert list of Pandoc inline elements to RST.
-inlineListToRST :: WriterOptions -> [Inline] -> State WriterState Doc
-inlineListToRST opts lst = mapM (inlineToRST opts) lst >>= return . hcat
+inlineListToRST :: [Inline] -> State WriterState Doc
+inlineListToRST lst = mapM inlineToRST lst >>= return . hcat
 
 -- | Convert Pandoc inline element to RST.
-inlineToRST :: WriterOptions -> Inline -> State WriterState Doc
-inlineToRST opts (Emph lst) = do 
-  contents <- inlineListToRST opts lst
+inlineToRST :: Inline -> State WriterState Doc
+inlineToRST (Emph lst) = do 
+  contents <- inlineListToRST lst
   return $ char '*' <> contents <> char '*'
-inlineToRST opts (Strong lst) = do
-  contents <- inlineListToRST opts lst
+inlineToRST (Strong lst) = do
+  contents <- inlineListToRST lst
   return $ text "**" <> contents <> text "**"
-inlineToRST opts (Strikeout lst) = do 
-  contents <- inlineListToRST opts lst
+inlineToRST (Strikeout lst) = do 
+  contents <- inlineListToRST lst
   return $ text "[STRIKEOUT:" <> contents <> char ']'
-inlineToRST opts (Superscript lst) = do 
-  contents <- inlineListToRST opts lst
+inlineToRST (Superscript lst) = do 
+  contents <- inlineListToRST lst
   return $ text "\\ :sup:`" <> contents <> text "`\\ "
-inlineToRST opts (Subscript lst) = do 
-  contents <- inlineListToRST opts lst
+inlineToRST (Subscript lst) = do 
+  contents <- inlineListToRST lst
   return $ text "\\ :sub:`" <> contents <> text "`\\ "
-inlineToRST opts (Quoted SingleQuote lst) = do
-  contents <- inlineListToRST opts lst
+inlineToRST (Quoted SingleQuote lst) = do
+  contents <- inlineListToRST lst
   return $ char '\'' <> contents <> char '\''
-inlineToRST opts (Quoted DoubleQuote lst) = do
-  contents <- inlineListToRST opts lst
+inlineToRST (Quoted DoubleQuote lst) = do
+  contents <- inlineListToRST lst
   return $ char '"' <> contents <> char '"'
-inlineToRST opts EmDash = return $ text "--"
-inlineToRST opts EnDash = return $ char '-'
-inlineToRST opts Apostrophe = return $ char '\''
-inlineToRST opts Ellipses = return $ text "..."
-inlineToRST opts (Code str) = return $ text $ "``" ++ str ++ "``"
-inlineToRST opts (Str str) = return $ text $ escapeString str
-inlineToRST opts (Math str) = return $ text $ "$" ++ str ++ "$"
-inlineToRST opts (TeX str) = return empty
-inlineToRST opts (HtmlInline str) = return empty
-inlineToRST opts (LineBreak) = return $ char ' ' -- RST doesn't have linebreaks 
-inlineToRST opts Space = return $ char ' '
-inlineToRST opts (Link [Code str] (src, tit)) | src == str ||
+inlineToRST EmDash = return $ text "--"
+inlineToRST EnDash = return $ char '-'
+inlineToRST Apostrophe = return $ char '\''
+inlineToRST Ellipses = return $ text "..."
+inlineToRST (Code str) = return $ text $ "``" ++ str ++ "``"
+inlineToRST (Str str) = return $ text $ escapeString str
+inlineToRST (Math str) = do
+  includes <- get >>= (return . stIncludes)
+  let rawMathRole = ".. role:: math(raw)\n\
+                    \   :format: html latex\n"
+  if not (rawMathRole `elem` includes)
+     then modify $ \st -> st { stIncludes = rawMathRole : includes }
+     else return ()
+  return $ text $ ":math:`$" ++ str ++ "$`"
+inlineToRST (TeX str) = return empty
+inlineToRST (HtmlInline str) = return empty
+inlineToRST (LineBreak) = do
+  return $ empty -- there's no line break in RST
+inlineToRST Space = return $ char ' '
+inlineToRST (Link [Code str] (src, tit)) | src == str ||
                                                 src == "mailto:" ++ str = do
   let srcSuffix = if isPrefixOf "mailto:" src then drop 7 src else src
   return $ text srcSuffix
-inlineToRST opts (Link txt (src, tit)) = do
-  let useReferenceLinks = writerReferenceLinks opts
-  linktext <- inlineListToRST opts $ normalizeSpaces txt
+inlineToRST (Link txt (src, tit)) = do
+  useReferenceLinks <- get >>= (return . writerReferenceLinks . stOptions)
+  linktext <- inlineListToRST $ normalizeSpaces txt
   if useReferenceLinks
-    then do (notes, refs, pics) <- get
+    then do refs <- get >>= (return . stLinks)
             let refs' = if (txt, (src, tit)) `elem` refs
                            then refs
                            else (txt, (src, tit)):refs
-            put (notes, refs', pics)
+            modify $ \st -> st { stLinks = refs' }
             return $ char '`' <> linktext <> text "`_"
     else return $ char '`' <> linktext <> text " <" <> text src <> text ">`_"
-inlineToRST opts (Image alternate (source, tit)) = do
-  (notes, refs, pics) <- get
+inlineToRST (Image alternate (source, tit)) = do
+  pics <- get >>= (return . stImages)
   let labelsUsed = map fst pics 
   let txt = if null alternate || alternate == [Str ""] || 
                alternate `elem` labelsUsed
-               then [Str $ "image" ++ show (length refs)]
+               then [Str $ "image" ++ show (length pics)]
                else alternate
   let pics' = if (txt, (source, tit)) `elem` pics
                  then pics
                  else (txt, (source, tit)):pics
-  put (notes, refs, pics')
-  label <- inlineListToRST opts txt
+  modify $ \st -> st { stImages = pics' }
+  label <- inlineListToRST txt
   return $ char '|' <> label <> char '|'
-inlineToRST opts (Note contents) = do 
+inlineToRST (Note contents) = do 
   -- add to notes in state
-  modify (\(notes, refs, pics) -> (contents:notes, refs, pics))
-  (notes, _, _) <- get
-  let ref = show $ (length notes)
+  notes <- get >>= (return . stNotes)
+  modify $ \st -> st { stNotes = contents:notes }
+  let ref = show $ (length notes) + 1
   return $ text " [" <> text ref <> text "]_"
diff --git a/debian/changelog b/debian/changelog
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,200 @@
+pandoc (0.46) unstable; urgency=low
+
+  [ John MacFarlane ]
+
+  * Made -H, -A, and -B options cumulative: if they are specified
+    multiple times, multiple files will be included.
+
+  * Added optional HTML sanitization using a whitelist.
+    When this option is specified (--sanitize-html on the command line),
+    unsafe HTML tags will be replaced by HTML comments, and unsafe HTML
+    attributes will be removed.  This option should be especially useful
+    for those who want to use pandoc libraries in web applications, where
+    users will provide the input.
+    
+    + Main.hs:  Added --sanitize-html option.
+
+    + Text.Pandoc.Shared:  Added stateSanitizeHTML to ParserState.
+
+    + Text.Pandoc.Readers.HTML:
+      - Added whitelists of sanitaryTags and sanitaryAttributes.
+      - Added parsers to check these lists (and state) to see if a given
+        tag or attribute should be counted unsafe.
+      - Modified anyHtmlTag and anyHtmlEndTag to replace unsafe tags
+        with comments.
+      - Modified htmlAttribute to remove unsafe attributes.
+      - Modified htmlScript and htmlStyle to remove these elements if
+        unsafe.
+
+    + Modified README and man pages to document new option.
+
+  * Improved handling of email addresses in markdown and reStructuredText.
+    Consolidated uri and email address parsers.  (Resolves Issue #37.)
+
+    + New emailAddress and uri parsers in Text.Pandoc.Shared.
+      - uri parser uses parseURI from Network.URI.
+      - emailAddress parser properly handles email addresses with periods
+        in them.
+
+    + Removed uri and emailAddress parsers from Text.Pandoc.Readers.RST
+      and Text.Pandoc.Readers.Markdown.
+
+  * Markdown reader:
+
+    + Fixed emph parser so that "*hi **there***" is parsed as a Strong
+      nested in an Emph. (A '*' is only recognized as the end of the
+      emphasis if it's not the beginning of a strong emphasis.)
+
+    + Moved blockQuote parser before list parsers for performance.
+
+    + Modified 'source' parser to allow backslash-escapes in URLs.
+      So, for example, [my](/url\(1\)) yields a link to /url(1).
+      Resolves Issue #34.
+
+    + Disallowed links within links. (Resolves Issue #35.)
+      - Replaced inlinesInBalanced with inlinesInBalancedBrackets, which 
+        instead of hard-coding the inline parser takes an inline parser
+        as a parameter.
+      - Modified reference and inlineNote to use inlinesInBalancedBrackets.
+      - Removed unneeded inlineString function.
+      - Added inlineNonLink parser, which is now used in the definition of
+        reference.
+      - Added inlineParsers list and redefined inline and inlineNonLink parsers
+        in terms of it.
+      - Added failIfLink parser.
+ 
+    + Better handling of parentheses in URLs and quotation marks in titles.
+      - 'source' parser first tries to parse URL with balanced parentheses;
+        if that doesn't work, it tries to parse everything beginning with
+        '(' and ending with ')'.
+      - source parser now uses an auxiliary function source'.
+      - linkTitle parser simplified and improved, under assumption that it
+        will be called in context of source'.
+
+    + Make 'block' conditional on strictness state, instead of using
+      failIfStrict in block parsers. Use a different ordering of parsers
+      in strict mode (raw HTML block before paragraph) for performance.
+      In non-strict mode use rawHtmlBlocks instead of htmlBlock.
+      Simplified htmlBlock, since we know it's only called in strict
+      mode.
+
+    + Improved handling of raw HTML.  (Resolves Issue #36.)
+      - Tags that can be either block or inline (e.g. <ins>) should
+        be treated as block when appropriate and as inline when
+        appropriate. Thus, for example,
+        <ins>hi</ins>
+        should be treated as a paragraph with inline <ins> tags, while
+        <ins>
+        hi
+        </ins>
+        should be treated as a paragraph within <ins> tags.
+      - Moved htmlBlock after para in list of block parsers.  This ensures
+        that tags that can be either block or inline get parsed as inline
+        when appropriate.
+      - Modified rawHtmlInline' so that block elements aren't treated as
+        inline.
+      - Modified para parser so that paragraphs containing only HTML tags and
+        blank space are not allowed.  Treat these as raw HTML blocks instead.
+
+    + Fixed bug wherein HTML preceding a code block could cause it to
+      be parsed as a paragraph.  The problem is that the HTML parser
+      used to eat all blank space after an HTML block, including the
+      indentation of the code block.  (Resolves Issue #39.)
+      - In Text.Pandoc.Readers.HTML, removed parsing of following space
+        from rawHtmlBlock.
+      - In Text.Pandoc.Readers.Markdown, modified rawHtmlBlocks so that
+        indentation is eaten *only* on the first line after the HTML
+        block.  This means that in
+        <div>
+             foo
+        <div>
+        the foo won't be treated as a code block, but in
+        <div>
+      
+            foo
+      
+        </div>
+        it will.  This seems the right approach for least surprise.
+
+  * RST reader:
+
+    + Fixed bug in parsing explicit links (resolves Issue #44).
+      The problem was that we were looking for inlines until a '<' character
+      signaled the start of the URL; so, if you hit a reference-style link,
+      it would keep looking til the end of the document.  Fix:  change
+      inline => (notFollowedBy (char '`') >> inline).  Note that this won't
+      allow code inlines in links, but these aren't allowed in resT anyway.
+
+    + Cleaned up parsing of reference names in key blocks and links.
+      Allow nonquoted reference links to contain isolated '.', '-', '_', so
+      so that strings like 'a_b_' count as links.
+
+    + Removed unnecessary check for following link in str.
+      This is unnecessary now that link is above str in the definition of
+      'inline'.
+     
+  * HTML reader:
+
+    + Modified rawHtmlBlock so it parses </html> and </body> tags.
+      This allows these tags to be handled correctly in Markdown.
+      HTML reader now uses rawHtmlBlock', which excludes </html> and </body>,
+      since these are handled in parseHtml.  (Resolves Issue #38.)
+
+    + Fixed bug (emph parser was looking for <IT> tag, not <I>).
+
+    + Don't interpret contents of style tags as markdown.
+      (Resolves Issue #40.)
+      - Added htmlStyle, analagous to htmlScript.
+      - Use htmlStyle in htmlBlockElement and rawHtmlInline.
+      - Moved "script" from the list of tags that can be either block or
+        inline to the list of block tags.
+
+    + Modified rawHtmlBlock to use anyHtmlBlockTag instead of anyHtmlTag
+      and anyHtmlEndTag.  This fixes a bug in markdown parsing, where
+      inline tags would be included in raw HTML blocks.
+
+    + Modified anyHtmlBlockTag to test for (not inline) rather than
+      directly for block.  This allows us to handle e.g. docbook in
+      the markdown reader.
+
+  * LaTeX reader:  Properly recognize --parse-raw in rawLaTeXInline.
+    Updated LaTeX reader test to use --parse-raw.
+
+  * HTML writer:
+
+    + Modified rules for automatic HTML header identifiers to
+      ensure that identifiers begin with an alphabetic character.
+      The new rules are described in README.  (Resolves Issue #33.)
+
+    + Changed handling of titles in HTML writer so you don't get
+      "titleprefix - " followed by nothing.
+
+  * ConTeXt writer: Use wrappers around Doc elements to ensure proper
+    spacing.  Each block element is wrapped with either Pad or Reg.
+    Pad'ed elements are guaranteed to have a blank line in between.
+
+  * RST writer:
+
+    + Refactored RST writer to use a record instead of a tuple for state,
+      and to include options in state so it doesn't need to be passed as
+      a parameter.
+
+    + Use an interpreted text role to render math in restructuredText.
+      See http://www.american.edu/econ/itex2mml/mathhack.rst for the
+      strategy.
+ 
+  [ Recai Oktaş ]
+
+  * Debian packaging changes:
+
+    + Remove the empty 'include' directory in -dev package, which lintian
+      complains about.
+    + Bump Standarts-Version to 3.7.3.
+    + Use new 'Homepage:' field to specify the upstream URL on suggestion of
+      lintian.
+
+ -- Recai Oktaş <roktas@debian.org>  Tue, 08 Jan 2008 05:13:31 +0200
+
 pandoc (0.45) unstable; urgency=low
 
   [ John MacFarlane ]
diff --git a/debian/control b/debian/control
--- a/debian/control
+++ b/debian/control
@@ -5,7 +5,8 @@
 Build-Depends: debhelper (>= 4.0.0), haskell-devscripts (>=0.5.12), ghc6 (>= 6.6-1), libghc6-xhtml-dev, libghc6-mtl-dev, libghc6-network-dev, perl
 Build-Depends-Indep: haddock
 Build-Conflicts: ghc6 (>= 6.8), ghc6 (<= 6.4)
-Standards-Version: 3.7.2.0
+Standards-Version: 3.7.3
+Homepage: http://johnmacfarlane.net/pandoc/
 XS-Vcs-Svn: http://pandoc.googlecode.com/svn/trunk
 XS-Vcs-Browser: http://pandoc.googlecode.com/svn/trunk
 
@@ -33,8 +34,6 @@
  representation of the document, and a set of writers, which convert
  this native representation into a target format. Thus, adding an input
  or output format requires only adding a reader or writer.
- .
-  Homepage: http://johnmacfarlane.net/pandoc/
 
 Package: libghc6-pandoc-dev
 Section: libdevel
@@ -62,8 +61,6 @@
  or output format requires only adding a reader or writer.
  .
  This package contains the libraries compiled for GHC 6.
- .
-  Homepage: http://johnmacfarlane.net/pandoc/
 
 Package: pandoc-doc
 Section: doc
@@ -89,5 +86,3 @@
  or output format requires only adding a reader or writer.
  .
  This package contains the library documentation for Pandoc.
- .
-  Homepage: http://johnmacfarlane.net/pandoc/
diff --git a/debian/rules b/debian/rules
--- a/debian/rules
+++ b/debian/rules
@@ -63,6 +63,8 @@
 
 	dh_haskell -a
 
+	# Remove empty directories, which lintian complains about.
+	find debian/libghc6-$(THIS)-dev -type d -name 'include' -empty -delete
 	# Hack!  Cabal builds executables while building libraries.  Move these
 	# files to top dir where the Makefile install target expects to find.
 	# See "BUGS" section at the following document:
diff --git a/man/man1/hsmarkdown.1.md b/man/man1/hsmarkdown.1.md
--- a/man/man1/hsmarkdown.1.md
+++ b/man/man1/hsmarkdown.1.md
@@ -1,6 +1,6 @@
 % HSMARKDOWN(1) Pandoc User Manuals
 % John MacFarlane
-% June 30, 2007
+% January 8, 2008
 
 # NAME
 
diff --git a/man/man1/html2markdown.1.md b/man/man1/html2markdown.1.md
--- a/man/man1/html2markdown.1.md
+++ b/man/man1/html2markdown.1.md
@@ -1,6 +1,6 @@
 % HTML2MARKDOWN(1) Pandoc User Manuals
 % John MacFarlane and Recai Oktas
-% June 30, 2007
+% January 8, 2008
 
 # NAME
 
@@ -50,6 +50,10 @@
 
 \--no-wrap
 :   Disable text wrapping in output.  (Default is to wrap text.)
+
+\--sanitize-html
+:   Sanitizes HTML using a whitelist. Unsafe tags are replaced by HTML
+    comments; unsafe attributes are omitted.
 
 -H *FILE*, \--include-in-header=*FILE*
 :   Include contents of *FILE* at the end of the header.  Implies
diff --git a/man/man1/markdown2pdf.1.md b/man/man1/markdown2pdf.1.md
--- a/man/man1/markdown2pdf.1.md
+++ b/man/man1/markdown2pdf.1.md
@@ -1,6 +1,6 @@
 % MARKDOWN2PDF(1) Pandoc User Manuals
 % John MacFarlane and Recai Oktas
-% June 30, 2007
+% January 8, 2008
 
 # NAME
 
diff --git a/man/man1/pandoc.1.md b/man/man1/pandoc.1.md
--- a/man/man1/pandoc.1.md
+++ b/man/man1/pandoc.1.md
@@ -1,6 +1,6 @@
 % PANDOC(1) Pandoc User Manuals
 % John MacFarlane
-% November 30, 2007 
+% January 8, 2008
 
 # NAME
 
@@ -125,6 +125,11 @@
 
 \--no-wrap
 :   Disable text wrapping in output. (Default is to wrap text.)
+
+\--sanitize-html
+:   Sanitizes HTML (in markdown or HTML input) using a whitelist.
+    Unsafe tags are replaced by HTML comments; unsafe attributes
+    are omitted.
 
 \--toc, \--table-of-contents
 :   Include an automatically generated table of contents (HTML, markdown,
diff --git a/pandoc.cabal b/pandoc.cabal
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,9 +1,9 @@
 Name:            pandoc
-Version:         0.45
+Version:         0.46
 Cabal-Version:   >= 1.2
 License:         GPL
 License-File:    COPYING
-Copyright:       (c) 2006-2007 John MacFarlane
+Copyright:       (c) 2006-2008 John MacFarlane
 Author:          John MacFarlane <jgm@berkeley.edu>
 Maintainer:      John MacFarlane <jgm@berkeley.edu>
 Stability:       alpha
diff --git a/pandoc.cabal.ghc66 b/pandoc.cabal.ghc66
--- a/pandoc.cabal.ghc66
+++ b/pandoc.cabal.ghc66
@@ -1,5 +1,5 @@
 Name:            pandoc
-Version:         0.45
+Version:         0.46
 License:         GPL
 License-File:    COPYING
 Copyright:       (c) 2006-2007 John MacFarlane
diff --git a/tests/runtests.pl b/tests/runtests.pl
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -99,7 +99,7 @@
 test_results("html reader", "tmp.native", "html-reader.native");
 
 print "Testing latex reader...";
-`$script -r latex -w native -s latex-reader.latex > tmp.native`;
+`$script -r latex -w native -R -s latex-reader.latex > tmp.native`;
 test_results("latex reader", "tmp.native", "latex-reader.native");
 
 print "Testing native reader...";
diff --git a/tests/tables.context b/tests/tables.context
--- a/tests/tables.context
+++ b/tests/tables.context
@@ -132,4 +132,3 @@
 \NC\AR
 \HL
 \stoptable
-
diff --git a/tests/writer.context b/tests/writer.context
--- a/tests/writer.context
+++ b/tests/writer.context
@@ -121,12 +121,10 @@
 E-mail style:
 
 \startblockquote
-
 This is a block quote. It is pretty short.
-
 \stopblockquote
-\startblockquote
 
+\startblockquote
 Code in a block quote:
 
 \starttyping
@@ -147,16 +145,14 @@
 Nested block quotes:
 
 \startblockquote
-
 nested
-
 \stopblockquote
-\startblockquote
 
+\startblockquote
 nested
-
 \stopblockquote
 \stopblockquote
+
 This should not be a block quote: 2 \lettermore{} 1.
 
 And a following paragraph.
@@ -207,13 +203,10 @@
 \startitemize
 \item 
   asterisk 1
-
 \item 
   asterisk 2
-
 \item 
   asterisk 3
-
 \stopitemize
 
 Pluses tight:
@@ -232,13 +225,10 @@
 \startitemize
 \item 
   Plus 1
-
 \item 
   Plus 2
-
 \item 
   Plus 3
-
 \stopitemize
 
 Minuses tight:
@@ -257,13 +247,10 @@
 \startitemize
 \item 
   Minus 1
-
 \item 
   Minus 2
-
 \item 
   Minus 3
-
 \stopitemize
 
 \subsubject{Ordered}
@@ -295,13 +282,10 @@
 \startitemize[n][stopper=.]
 \item 
   First
-
 \item 
   Second
-
 \item 
   Third
-
 \stopitemize
 
 and using spaces:
@@ -309,13 +293,10 @@
 \startitemize[n][stopper=.]
 \item 
   One
-
 \item 
   Two
-
 \item 
   Three
-
 \stopitemize
 
 Multiple paragraphs:
@@ -323,16 +304,13 @@
 \startitemize[n][stopper=.]
 \item 
   Item 1, graf one.
-
+  
   Item 1. graf two. The quick brown fox jumped over the lazy dog's
   back.
-
 \item 
   Item 2.
-
 \item 
   Item 3.
-
 \stopitemize
 
 \subsubject{Nested}
@@ -347,9 +325,7 @@
     \item 
       Tab
     \stopitemize
-
   \stopitemize
-
 \stopitemize
 
 Here's another:
@@ -367,7 +343,6 @@
   \item 
     Foe
   \stopitemize
-
 \item 
   Third
 \stopitemize
@@ -377,10 +352,9 @@
 \startitemize[n][stopper=.]
 \item 
   First
-
 \item 
   Second:
-
+  
   \startitemize
   \item 
     Fee
@@ -389,10 +363,8 @@
   \item 
     Foe
   \stopitemize
-
 \item 
   Third
-
 \stopitemize
 
 \subsubject{Tabs and spaces}
@@ -400,19 +372,15 @@
 \startitemize
 \item 
   this is a list item indented with tabs
-
 \item 
   this is a list item indented with spaces
-
+  
   \startitemize
   \item 
     this is an example list item indented with tabs
-
   \item 
     this is an example list item indented with spaces
-
   \stopitemize
-
 \stopitemize
 
 \subsubject{Fancy list markers}
@@ -422,9 +390,9 @@
   begins with 2
 \item 
   and now 3
-
+  
   with a continuation
-
+  
   \startitemize[r][start=4,stopper=.,width=2.0em]
   \item 
     sublist with roman numerals, starting with 4
@@ -436,9 +404,7 @@
     \item 
       a subsublist
     \stopitemize
-
   \stopitemize
-
 \stopitemize
 
 Nesting:
@@ -456,11 +422,8 @@
       \item 
         Lower alpha with paren
       \stopitemize
-
     \stopitemize
-
   \stopitemize
-
 \stopitemize
 
 Autonumbering:
@@ -474,7 +437,6 @@
   \item 
     Nested.
   \stopitemize
-
 \stopitemize
 
 Should not be a list item:
@@ -492,9 +454,11 @@
 \startdescr{apple}
 red fruit
 \stopdescr
+
 \startdescr{orange}
 orange fruit
 \stopdescr
+
 \startdescr{banana}
 yellow fruit
 \stopdescr
@@ -504,9 +468,11 @@
 \startdescr{apple}
 red fruit
 \stopdescr
+
 \startdescr{orange}
 orange fruit
 \stopdescr
+
 \startdescr{banana}
 yellow fruit
 \stopdescr
@@ -515,15 +481,14 @@
 
 \startdescr{apple}
 red fruit
-
 \stopdescr
+
 \startdescr{orange}
 orange fruit
-
 \stopdescr
+
 \startdescr{banana}
 yellow fruit
-
 \stopdescr
 
 Multiple blocks with italics:
@@ -532,8 +497,8 @@
 red fruit
 
 contains seeds, crisp, pleasant to taste
-
 \stopdescr
+
 \startdescr{{\em orange}}
 orange fruit
 
@@ -542,9 +507,7 @@
 \stoptyping
 
 \startblockquote
-
 orange block quote
-
 \stopblockquote
 \stopdescr
 
@@ -777,8 +740,7 @@
 Here's a link with an amersand in the link text:
 \useURL[24][http://att.com/][][AT\&T]\from[24].
 
-Here's an
-\useURL[25][/script?foo=1&bar=2][][inline link]\from[25].
+Here's an \useURL[25][/script?foo=1&bar=2][][inline link]\from[25].
 
 Here's an
 \useURL[26][/script?foo=1&bar=2][][inline link in pointy braces]\from[26].
@@ -801,11 +763,10 @@
 \useURL[29][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[29]
 
 \startblockquote
-
 Blockquoted:
 \useURL[30][http://example.com/][][http://example.com/]\from[30]
-
 \stopblockquote
+
 Auto-links should not occur here: \type{<http://example.com/>}
 
 \starttyping
@@ -857,11 +818,10 @@
 verbatim characters, as well as [bracketed text].}
 
 \startblockquote
-
 Notes can go in quotes.
 \footnote{In quote.}
-
 \stopblockquote
+
 \startitemize[n][stopper=.]
 \item 
   And in list items.
@@ -870,6 +830,5 @@
 
 This paragraph should not be part of the note, as it is not
 indented.
-
 \stoptext
 
diff --git a/tests/writer.rst b/tests/writer.rst
--- a/tests/writer.rst
+++ b/tests/writer.rst
@@ -6,6 +6,9 @@
 :Author: Anonymous
 :Date: July 17, 2006
 
+.. role:: math(raw)
+   :format: html latex
+
 This is a set of tests for pandoc. Most of them are adapted from
 John Gruber's markdown test suite.
 
@@ -620,14 +623,14 @@
 
 - 
 - 
--  $2+2=4$
--  $x \in y$
--  $\alpha \wedge \omega$
--  $223$
--  $p$-Tree
--  $\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$
+-  :math:`$2+2=4$`
+-  :math:`$x \in y$`
+-  :math:`$\alpha \wedge \omega$`
+-  :math:`$223$`
+-  :math:`$p$`-Tree
+-  :math:`$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$`
 -  Here's one that has a line break in it:
-   $\alpha + \omega \times x^2$.
+   :math:`$\alpha + \omega \times x^2$`.
 
 These shouldn't be math:
 
diff --git a/web/index.txt.in b/web/index.txt.in
--- a/web/index.txt.in
+++ b/web/index.txt.in
@@ -157,7 +157,6 @@
 [GHC]:  http://www.haskell.org/ghc/
 [GPL]:  http://www.gnu.org/copyleft/gpl.html
 [Source tarball]: http://code.google.com/p/pandoc/downloads/detail?name=pandoc-@VERSION@.tar.gz "Download source tarball from Pandoc's Google Code site"
-[MacOS X binary package]: http://code.google.com/p/pandoc/downloads/detail?name=pandoc-@VERSION@.dmg "Download Mac OS X disk image from Pandoc's Google Code site"
 [Windows binary package]: http://code.google.com/p/pandoc/downloads/detail?name=pandoc-@VERSION@.zip "Download Windows zip file from Pandoc's Google Code site"
 [Debian unstable]: http://packages.debian.org/unstable/text/pandoc
 [FreeBSD ports]: http://www.freshports.org/textproc/pandoc/
