diff --git a/Text/HTML/Parser.hs b/Text/HTML/Parser.hs
deleted file mode 100644
--- a/Text/HTML/Parser.hs
+++ /dev/null
@@ -1,406 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE LambdaCase #-}
-
-{-# OPTIONS_GHC -O2 #-}
-
--- | This is a performance-oriented HTML tokenizer aim at web-crawling
--- applications. It follows the HTML5 parsing specification quite closely,
--- so it behaves reasonable well on ill-formed documents from the open Web.
---
-module Text.HTML.Parser
-    ( -- * Parsing
-      parseTokens
-    , parseTokensLazy
-    , token
-      -- * Types
-    , Token(..)
-    , TagName, AttrName, AttrValue
-    , Attr(..)
-      -- * Rendering, text canonicalization
-    , renderTokens
-    , renderToken
-    , renderAttrs
-    , renderAttr
-    , canonicalizeTokens
-    ) where
-
-import Data.Char hiding (isSpace)
-import Data.List (unfoldr)
-import GHC.Generics
-import Control.Applicative
-import Data.Monoid
-import Control.Monad (guard)
-import Control.DeepSeq
-
-import Data.Attoparsec.Text
-import qualified Data.Attoparsec.Text.Lazy as AL
-import Data.Text (Text)
-import qualified Data.Text as T
-import qualified Data.Text.Lazy as TL
-import Data.Text.Lazy.Builder (Builder)
-import qualified Data.Text.Lazy.Builder as B
-import Prelude hiding (take, takeWhile)
-
--- Section numbers refer to W3C HTML 5.2 specification.
-
--- | A tag name (e.g. @body@)
-type TagName   = Text
-
--- | An attribute name (e.g. @href@)
-type AttrName  = Text
-
--- | The value of an attribute
-type AttrValue = Text
-
--- | An HTML token
-data Token
-  -- | An opening tag. Attribute ordering is arbitrary.
-  = TagOpen !TagName [Attr]
-  -- | A self-closing tag.
-  | TagSelfClose !TagName [Attr]
-  -- | A closing tag.
-  | TagClose !TagName
-  -- | The content between tags.
-  | ContentText !Text
-  -- | A single character of content
-  | ContentChar !Char
-  -- | Contents of a comment.
-  | Comment !Builder
-  -- | Doctype
-  | Doctype !Text
-  deriving (Show, Ord, Eq, Generic)
-
--- | This is a bit of a hack
-endOfFileToken :: Token
-endOfFileToken = ContentText ""
-
--- | An attribute of a tag
-data Attr = Attr !AttrName !AttrValue
-          deriving (Show, Eq, Ord)
-
-instance NFData Token where
-    rnf (Comment b) = rnf $ B.toLazyText b
-    rnf _           = ()
-
--- | Parse a single 'Token'.
-token :: Parser Token
-token = dataState -- Start in the data state.
-
--- | /§8.2.4.1/: Data state
-dataState :: Parser Token
-dataState = do
-    content <- takeWhile (/= '<')
-    if not $ T.null content
-      then return $ ContentText content
-      else char '<' >> tagOpen
-
--- | /§8.2.4.6/: Tag open state
-tagOpen :: Parser Token
-tagOpen =
-        (char '!' >> markupDeclOpen)
-    <|> (char '/' >> endTagOpen)
-    <|> (char '?' >> bogusComment mempty)
-    <|> tagNameOpen
-    <|> other
-  where
-    other = do
-        return $ ContentChar '<'
-
--- | /§8.2.4.7/: End tag open state
-endTagOpen :: Parser Token
-endTagOpen = tagNameClose
-
--- | Equivalent to @inClass "\x09\x0a\x0c "@
-isWhitespace :: Char -> Bool
-isWhitespace '\x09' = True
-isWhitespace '\x0a' = True
-isWhitespace '\x0c' = True
-isWhitespace ' '    = True
-isWhitespace _      = False
-
-orC :: (Char -> Bool) -> (Char -> Bool) -> Char -> Bool
-orC f g c = f c || g c
-{-# INLINE orC #-}
-
-isC :: Char -> Char -> Bool
-isC = (==)
-{-# INLINE isC #-}
-
--- | /§8.2.4.8/: Tag name state: the open case
---
--- deviation: no lower-casing, don't handle NULL characters
-tagNameOpen :: Parser Token
-tagNameOpen = do
-    tag <- tagName'
-    id $  (satisfy isWhitespace >> beforeAttrName tag [])
-      <|> (char '/' >> selfClosingStartTag tag [])
-      <|> (char '>' >> return (TagOpen tag []))
-
--- | /§8.2.4.10/: Tag name state: close case
-tagNameClose :: Parser Token
-tagNameClose = do
-    tag <- tagName'
-    char '>' >> return (TagClose tag)
-
--- | /§8.2.4.10/: Tag name state: common code
---
--- deviation: no lower-casing, don't handle NULL characters
-tagName' :: Parser Text
-tagName' = do
-    c <- peekChar'
-    guard $ isAsciiUpper c || isAsciiLower c
-    takeWhile $ not . (isWhitespace `orC` isC '/' `orC` isC '<' `orC` isC '>')
-
--- | /§8.2.4.40/: Self-closing start tag state
-selfClosingStartTag :: TagName -> [Attr] -> Parser Token
-selfClosingStartTag tag attrs = do
-        (char '>' >> return (TagSelfClose tag attrs))
-    <|> (endOfInput >> return endOfFileToken)
-    <|> beforeAttrName tag attrs
-
--- | /§8.2.4.32/: Before attribute name state
---
--- deviation: no lower-casing
-beforeAttrName :: TagName -> [Attr] -> Parser Token
-beforeAttrName tag attrs = do
-    skipWhile isWhitespace
-    id $  (char '/' >> selfClosingStartTag tag attrs)
-      <|> (char '>' >> return (TagOpen tag attrs))
-      -- <|> (char '\x00' >> attrName tag attrs) -- TODO: NULL
-      <|> attrName tag attrs
-
--- | /§8.2.4.33/: Attribute name state
-attrName :: TagName -> [Attr] -> Parser Token
-attrName tag attrs = do
-    name <- takeWhile $ not . (isWhitespace `orC` isC '/' `orC` isC '=' `orC` isC '>')
-    id $  (endOfInput >> afterAttrName tag attrs name)
-      <|> (char '=' >> beforeAttrValue tag attrs name)
-      <|> try (do mc <- peekChar
-                  case mc of
-                    Just c | notNameChar c ->  afterAttrName tag attrs name
-                    _ -> empty)
-      -- <|> -- TODO: NULL
-  where notNameChar = isWhitespace `orC` isC '/' `orC` isC '>'
-
--- | /§8.2.4.34/: After attribute name state
-afterAttrName :: TagName -> [Attr] -> AttrName -> Parser Token
-afterAttrName tag attrs name = do
-    skipWhile isWhitespace
-    id $  (char '/' >> selfClosingStartTag tag attrs)
-      <|> (char '=' >> beforeAttrValue tag attrs name)
-      <|> (char '>' >> return (TagOpen tag (Attr name T.empty : attrs)))
-      <|> (endOfInput >> return endOfFileToken)
-      <|> attrName tag (Attr name T.empty : attrs)  -- not exactly sure this is right
-
--- | /§8.2.4.35/: Before attribute value state
-beforeAttrValue :: TagName -> [Attr] -> AttrName -> Parser Token
-beforeAttrValue tag attrs name = do
-    skipWhile isWhitespace
-    id $  (char '"' >> attrValueDQuoted tag attrs name)
-      <|> (char '\'' >> attrValueSQuoted tag attrs name)
-      <|> (char '>' >> return (TagOpen tag (Attr name T.empty : attrs)))
-      <|> attrValueUnquoted tag attrs name
-
--- | /§8.2.4.36/: Attribute value (double-quoted) state
-attrValueDQuoted :: TagName -> [Attr] -> AttrName -> Parser Token
-attrValueDQuoted tag attrs name = do
-    value <- takeWhile (/= '"')
-    _ <- char '"'
-    afterAttrValueQuoted tag attrs name value
-
--- | /§8.2.4.37/: Attribute value (single-quoted) state
-attrValueSQuoted :: TagName -> [Attr] -> AttrName -> Parser Token
-attrValueSQuoted tag attrs name = do
-    value <- takeWhile (/= '\'')
-    _ <- char '\''
-    afterAttrValueQuoted tag attrs name value
-
--- | /§8.2.4.38/: Attribute value (unquoted) state
-attrValueUnquoted :: TagName -> [Attr] -> AttrName -> Parser Token
-attrValueUnquoted tag attrs name = do
-    value <- takeTill $ isWhitespace `orC` isC '>'
-    id $  (satisfy isWhitespace >> beforeAttrName tag attrs) -- unsure: don't emit?
-      <|> (char '>' >> return (TagOpen tag (Attr name value : attrs)))
-      <|> (endOfInput >> return endOfFileToken)
-
--- | /§8.2.4.39/: After attribute value (quoted) state
-afterAttrValueQuoted :: TagName -> [Attr] -> AttrName -> AttrValue -> Parser Token
-afterAttrValueQuoted tag attrs name value =
-          (satisfy isWhitespace >> beforeAttrName tag attrs')
-      <|> (char '/' >> selfClosingStartTag tag attrs')
-      <|> (char '>' >> return (TagOpen tag attrs'))
-      <|> (endOfInput >> return endOfFileToken)
-  where attrs' = Attr name value : attrs
-
--- | /§8.2.4.41/: Bogus comment state
-bogusComment :: Builder -> Parser Token
-bogusComment content = do
-        (char '>' >> return (Comment content))
-    <|> (endOfInput >> return (Comment content))
-    <|> (char '\x00' >> bogusComment (content <> "\xfffd"))
-    <|> (anyChar >>= \c -> bogusComment (content <> B.singleton c))
-
--- | /§8.2.4.42/: Markup declaration open state
-markupDeclOpen :: Parser Token
-markupDeclOpen =
-        try comment_
-    <|> try docType
-    <|> bogusComment mempty
-  where
-    comment_ = char '-' >> char '-' >> commentStart
-    docType = do
-        -- switching this to asciiCI slowed things down by a factor of two
-        s <- take 7
-        guard $ T.toLower s == "doctype"
-        doctype
-
--- | /§8.2.4.43/: Comment start state
-commentStart :: Parser Token
-commentStart = do
-          (char '-' >> commentStartDash)
-      <|> (char '>' >> return (Comment mempty))
-      <|> comment mempty
-
--- | /§8.2.4.44/: Comment start dash state
-commentStartDash :: Parser Token
-commentStartDash =
-          (char '-' >> commentEnd mempty)
-      <|> (char '>' >> return (Comment mempty))
-      <|> (endOfInput >> return (Comment mempty))
-      <|> (comment (B.singleton '-'))
-
--- | /§8.2.4.45/: Comment state
-comment :: Builder -> Parser Token
-comment content0 = do
-    content <- B.fromText <$> takeWhile (not . (isC '-' `orC` isC '\x00' `orC` isC '<'))
-    id $  (char '<' >> commentLessThan (content0 <> content <> "<"))
-      <|> (char '-' >> commentEndDash (content0 <> content))
-      <|> (char '\x00' >> comment (content0 <> content <> B.singleton '\xfffd'))
-      <|> (endOfInput >> return (Comment $ content0 <> content))
-
--- | /§8.2.46/: Comment less-than sign state
-commentLessThan :: Builder -> Parser Token
-commentLessThan content =
-        (char '!' >> commentLessThanBang (content <> "!"))
-    <|> (char '<' >> commentLessThan (content <> "<"))
-    <|> comment content
-
--- | /§8.2.47/: Comment less-than sign bang state
-commentLessThanBang :: Builder -> Parser Token
-commentLessThanBang content =
-        (char '-' >> commentLessThanBangDash content)
-    <|> comment content
-
--- | /§8.2.48/: Comment less-than sign bang dash state
-commentLessThanBangDash :: Builder -> Parser Token
-commentLessThanBangDash content =
-        (char '-' >> commentLessThanBangDashDash content)
-    <|> commentEndDash content
-
--- | /§8.2.49/: Comment less-than sign bang dash dash state
-commentLessThanBangDashDash :: Builder -> Parser Token
-commentLessThanBangDashDash content =
-        (char '>' >> comment content)
-    <|> (endOfInput >> comment content)
-    <|> commentEnd content
-
--- | /§8.2.4.50/: Comment end dash state
-commentEndDash :: Builder -> Parser Token
-commentEndDash content = do
-        (char '-' >> commentEnd content)
-    <|> (endOfInput >> return (Comment content))
-    <|> (comment (content <> "-"))
-
--- | /§8.2.4.51/: Comment end state
-commentEnd :: Builder -> Parser Token
-commentEnd content = do
-        (char '>' >> return (Comment content))
-    <|> (char '!' >> commentEndBang content)
-    <|> (char '-' >> commentEnd (content <> "-"))
-    <|> (endOfInput >> return (Comment content))
-    <|> (comment (content <> "--"))
-
--- | /§8.2.4.52/: Comment end bang state
-commentEndBang :: Builder -> Parser Token
-commentEndBang content = do
-        (char '-' >> commentEndDash (content <> "--!"))
-    <|> (char '>' >> return (Comment content))
-    <|> (endOfInput >> return (Comment content))
-    <|> (comment (content <> "--!"))
-
--- | /§8.2.4.53/: DOCTYPE state
--- FIXME
-doctype :: Parser Token
-doctype = do
-    content <- takeTill (=='>')
-    _ <- char '>'
-    return $ Doctype content
-
--- | Parse a lazy list of tokens from strict 'Text'.
-parseTokens :: Text -> [Token]
-parseTokens = unfoldr f
-  where
-    f :: Text -> Maybe (Token, Text)
-    f t
-      | T.null t = Nothing
-      | otherwise =
-        case parse token t of
-            Done rest tok -> Just (tok, rest)
-            Partial cont  ->
-                case cont mempty of
-                  Done rest tok -> Just (tok, rest)
-                  _             -> Nothing
-            _             -> Nothing
-
--- | Parse a lazy list of tokens from lazy 'TL.Text'.
-parseTokensLazy :: TL.Text -> [Token]
-parseTokensLazy = unfoldr f
-  where
-    f :: TL.Text -> Maybe (Token, TL.Text)
-    f t
-      | TL.null t = Nothing
-      | otherwise =
-        case AL.parse token t of
-            AL.Done rest tok -> Just (tok, rest)
-            _                -> Nothing
-
--- | See 'renderToken'.
-renderTokens :: [Token] -> TL.Text
-renderTokens = mconcat . fmap renderToken
-
--- | (Somewhat) canonical string representation of 'Token'.
-renderToken :: Token -> TL.Text
-renderToken = TL.fromStrict . mconcat . \case
-    (TagOpen n [])         -> ["<", n, ">"]
-    (TagOpen n attrs)      -> ["<", n, " ", renderAttrs attrs, ">"]
-    (TagSelfClose n attrs) -> ["<", n, " ", renderAttrs attrs, " />"]
-    (TagClose n)           -> ["</", n, ">"]
-    (ContentChar c)        -> [T.singleton c]
-    (ContentText t)        -> [t]
-    (Comment builder)      -> ["<!--", TL.toStrict $ B.toLazyText builder, "-->"]
-    (Doctype t)            -> ["<!DOCTYPE", t, ">"]
-
--- | See 'renderAttr'.
-renderAttrs :: [Attr] -> Text
-renderAttrs = T.unwords . fmap renderAttr . reverse
-
--- | Does not escape quotation in attribute values!
-renderAttr :: Attr -> Text
-renderAttr (Attr k v) = mconcat [k, "=\"", v, "\""]
-
--- | Meld neighoring 'ContentChar' and 'ContentText' constructors together and drops empty text
--- elements.
-canonicalizeTokens :: [Token] -> [Token]
-canonicalizeTokens = filter (/= ContentText "") . meldTextTokens
-
-meldTextTokens :: [Token] -> [Token]
-meldTextTokens = concatTexts . fmap charToText
-  where
-    charToText (ContentChar c) = ContentText (T.singleton c)
-    charToText t = t
-
-    concatTexts = \case
-      (ContentText t : ContentText t' : ts) -> concatTexts $ ContentText (t <> t') : ts
-      (t : ts) -> t : concatTexts ts
-      [] -> []
diff --git a/Text/HTML/Tree.hs b/Text/HTML/Tree.hs
deleted file mode 100644
--- a/Text/HTML/Tree.hs
+++ /dev/null
@@ -1,71 +0,0 @@
-{-# LANGUAGE OverloadedStrings     #-}
-{-# LANGUAGE ViewPatterns          #-}
-
-module Text.HTML.Tree
-    ( -- * Constructing forests
-      tokensToForest
-    , ParseTokenForestError(..), PStack(..)
-    , nonClosing
-      -- * Deconstructing forests
-    , tokensFromForest
-    , tokensFromTree
-    ) where
-
-import           Data.Monoid
-import           Data.Text (Text)
-import           Data.Tree
-import           Text.HTML.Parser
-
-
-tokensToForest :: [Token] -> Either ParseTokenForestError (Forest Token)
-tokensToForest = f (PStack [] [])
-  where
-    f (PStack ss []) [] = Right (reverse ss)
-    f pstack []         = Left $ ParseTokenForestErrorBracketMismatch pstack Nothing
-    f pstack (t : ts)   = case t of
-        TagOpen n _     -> if n `elem` nonClosing
-                             then f (pushFlatSibling t pstack) ts
-                             else f (pushParent t pstack) ts
-        TagSelfClose {} -> f (pushFlatSibling t pstack) ts
-        TagClose n      -> (`f` ts) =<< popParent n pstack
-        ContentChar _   -> f (pushFlatSibling t pstack) ts
-        ContentText _   -> f (pushFlatSibling t pstack) ts
-        Comment _       -> f (pushFlatSibling t pstack) ts
-        Doctype _       -> f (pushFlatSibling t pstack) ts
-
-nonClosing :: [Text]
-nonClosing = ["br", "hr", "img"]
-
-data ParseTokenForestError =
-    ParseTokenForestErrorBracketMismatch PStack (Maybe Token)
-  deriving (Eq, Show)
-
-data PStack = PStack
-    { _pstackToplevelSiblings :: Forest Token
-    , _pstackParents          :: [(Token, Forest Token)]
-    }
-  deriving (Eq, Show)
-
-pushParent :: Token -> PStack -> PStack
-pushParent t (PStack ss ps) = PStack [] ((t, ss) : ps)
-
-popParent :: TagName -> PStack -> Either ParseTokenForestError PStack
-popParent n (PStack ss ((p@(TagOpen n' _), ss') : ps))
-    | n == n' = Right $ PStack (Node p (reverse ss) : ss') ps
-popParent n pstack
-    = Left $ ParseTokenForestErrorBracketMismatch pstack (Just $ TagClose n)
-
-pushFlatSibling :: Token -> PStack -> PStack
-pushFlatSibling t (PStack ss ps) = PStack (Node t [] : ss) ps
-
-
-tokensFromForest :: Forest Token -> [Token]
-tokensFromForest = mconcat . fmap tokensFromTree
-
-tokensFromTree :: Tree Token -> [Token]
-tokensFromTree (Node o@(TagOpen n _) ts) | n `notElem` nonClosing
-    = [o] <> tokensFromForest ts <> [TagClose n]
-tokensFromTree (Node t [])
-    = [t]
-tokensFromTree _
-    = error "renderTokenTree: leaf node with children."
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,15 @@
+module Main where
+
+import Control.Monad
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import Text.HTML.Parser
+import System.Environment
+
+main :: IO ()
+main = do 
+    files <- getArgs
+    forM_ files $ \fname -> do
+        t <- T.readFile fname
+        print $ length $ parseTokens t
+
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,10 @@
+# Changelog for `html-parse`
+
+## 0.2.1.0
+
+- Added support for decoding of character references (#18)
+- All self-closing elements are now recognized as such
+
+## Earlier
+
+There be dragons.
diff --git a/html-parse.cabal b/html-parse.cabal
--- a/html-parse.cabal
+++ b/html-parse.cabal
@@ -1,5 +1,5 @@
 name:                html-parse
-version:             0.2.0.2
+version:             0.2.1.0
 synopsis:            A high-performance HTML tokenizer
 description:
     This package provides a fast and reasonably robust HTML5 tokenizer built
@@ -52,7 +52,8 @@
 category:            Text
 build-type:          Simple
 cabal-version:       >=1.10
-tested-with:         GHC==8.0.2, GHC==7.10.3, GHC==7.8.4
+tested-with:         GHC==8.4.*, GHC==8.6.*, GHC==8.8.*, GHC==8.10.*, GHC==9.0.*, GHC==9.2.*, GHC==9.4.*
+extra-source-files:  changelog.md
 
 
 source-repository head
@@ -61,13 +62,15 @@
 
 library
   exposed-modules:     Text.HTML.Parser, Text.HTML.Tree
+  other-modules:       Text.HTML.Parser.Entities, Data.Trie
   ghc-options:         -Wall
+  hs-source-dirs:      src
   other-extensions:    OverloadedStrings, DeriveGeneric
-  build-depends:       base >=4.7 && <4.13,
-                       deepseq >=1.3 && <1.5,
-                       attoparsec >=0.13 && <0.14,
-                       text >=1.2 && <1.3,
-                       containers >=0.5 && <0.7
+  build-depends:       base >=4.7 && <4.20,
+                       deepseq >=1.3 && <1.6,
+                       attoparsec >=0.13 && <0.15,
+                       text >=1.2 && <2.2,
+                       containers >=0.5 && <0.8
   default-language:    Haskell2010
 
 benchmark bench
@@ -79,7 +82,8 @@
                        attoparsec,
                        text,
                        tagsoup >= 0.13,
-                       criterion >= 1.1
+                       criterion >= 1.1,
+                       html-parse
   default-language:    Haskell2010
 
 test-suite spec
@@ -88,6 +92,7 @@
   main-is:             Spec.hs
   other-modules:       Text.HTML.ParserSpec, Text.HTML.TreeSpec
   ghc-options:         -Wall -with-rtsopts=-T
+  build-tool-depends:  hspec-discover:hspec-discover
   build-depends:       base,
                        containers,
                        hspec,
@@ -96,5 +101,14 @@
                        QuickCheck,
                        quickcheck-instances,
                        string-conversions,
+                       text
+  default-language:    Haskell2010
+
+-- For performance characterisation during optimisation
+executable html-parse-length
+  main-is:             app/Main.hs
+  buildable:           False
+  build-depends:       base,
+                       html-parse,
                        text
   default-language:    Haskell2010
diff --git a/src/Data/Trie.hs b/src/Data/Trie.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Trie.hs
@@ -0,0 +1,34 @@
+module Data.Trie
+    ( Trie
+    , singleton, fromList
+    , terminal, step
+    ) where
+
+import Control.Applicative
+
+import qualified Data.Map.Strict as M
+
+data Trie k v
+    = TrieNode !(Maybe v) !(M.Map k (Trie k v))
+
+instance Ord k => Monoid (Trie k v) where
+    mempty = TrieNode Nothing M.empty
+
+instance Ord k => Semigroup (Trie k v) where
+    TrieNode v0 ys0 <> TrieNode v1 ys1 =
+        TrieNode (v1 <|> v0) (M.unionWith (<>) ys0 ys1)
+
+singleton :: Ord k => [k] -> v -> Trie k v
+singleton = go
+  where
+    go [] v = TrieNode (Just v) M.empty
+    go (x:xs) v = TrieNode Nothing (M.singleton x (go xs v))
+
+fromList :: Ord k => [([k], v)] -> Trie k v
+fromList = foldMap (uncurry singleton)
+
+terminal :: Trie k v -> Maybe v
+terminal (TrieNode v _) = v
+
+step :: Ord k => k -> Trie k v -> Trie k v
+step k (TrieNode _ xs) = M.findWithDefault mempty k xs
diff --git a/src/Text/HTML/Parser.hs b/src/Text/HTML/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/Parser.hs
@@ -0,0 +1,430 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE LambdaCase #-}
+
+{-# OPTIONS_GHC -O2 #-}
+
+-- | This is a performance-oriented HTML tokenizer aim at web-crawling
+-- applications. It follows the HTML5 parsing specification quite closely,
+-- so it behaves reasonable well on ill-formed documents from the open Web.
+--
+module Text.HTML.Parser
+    ( -- * Parsing
+      parseTokens
+    , parseTokensLazy
+    , token
+      -- * Types
+    , Token(..)
+    , TagName, AttrName, AttrValue
+    , Attr(..)
+      -- * Rendering, text canonicalization
+    , renderTokens
+    , renderToken
+    , renderAttrs
+    , renderAttr
+    , canonicalizeTokens
+    ) where
+
+import Data.Char hiding (isSpace)
+import Data.List (unfoldr)
+import GHC.Generics
+import Control.Applicative
+import Data.Monoid
+import Control.Monad (guard)
+import Control.DeepSeq
+
+import Data.Attoparsec.Text
+import qualified Data.Attoparsec.Text.Lazy as AL
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+import Data.Text.Lazy.Builder (Builder)
+import qualified Data.Text.Lazy.Builder as B
+import Prelude hiding (take, takeWhile)
+
+import Text.HTML.Parser.Entities (entities)
+import qualified Data.Trie as Trie
+
+-- Section numbers refer to W3C HTML 5.2 specification.
+
+-- | A tag name (e.g. @body@)
+type TagName   = Text
+
+-- | An attribute name (e.g. @href@)
+type AttrName  = Text
+
+-- | The value of an attribute
+type AttrValue = Text
+
+-- | An HTML token
+data Token
+  -- | An opening tag. Attribute ordering is arbitrary. Void elements have a 'TagOpen' but no corresponding 'TagClose'. See 'Text.HTML.Tree.nonClosing'.
+  = TagOpen !TagName [Attr]
+  -- | A self-closing tag.
+  | TagSelfClose !TagName [Attr]
+  -- | A closing tag.
+  | TagClose !TagName
+  -- | The content between tags.
+  | ContentText !Text
+  -- | A single character of content
+  | ContentChar !Char
+  -- | Contents of a comment.
+  | Comment !Builder
+  -- | Doctype
+  | Doctype !Text
+  deriving (Show, Ord, Eq, Generic)
+
+-- | This is a bit of a hack
+endOfFileToken :: Token
+endOfFileToken = ContentText ""
+
+-- | An attribute of a tag
+data Attr = Attr !AttrName !AttrValue
+          deriving (Show, Eq, Ord)
+
+instance NFData Token where
+    rnf (Comment b) = rnf $ B.toLazyText b
+    rnf _           = ()
+
+-- | Parse a single 'Token'.
+token :: Parser Token
+token = dataState -- Start in the data state.
+
+-- | /§8.2.4.1/: Data state
+dataState :: Parser Token
+dataState = do
+    content <- takeWhile (\c -> c /= '<' && c /= '&')
+    if not $ T.null content
+      then return $ ContentText content
+      else choice
+        [ char '<' >> tagOpen
+        , try $ char '&' >> charRef
+        , ContentChar '&' <$ char '&'
+        ]
+
+charRef :: Parser Token
+charRef = go entityTrie
+  where
+    go :: Trie.Trie Char Token -> Parser Token
+    go trie = do
+      c <- anyChar
+      case c of
+        ';' -> maybe empty return (Trie.terminal trie)
+        _ -> go (Trie.step c trie)
+
+entityTrie :: Trie.Trie Char Token
+entityTrie = Trie.fromList
+    [ (T.unpack name, ContentText expansion)
+    | (name, expansion) <- entities
+    ]
+
+-- | /§8.2.4.6/: Tag open state
+tagOpen :: Parser Token
+tagOpen =
+        (char '!' >> markupDeclOpen)
+    <|> (char '/' >> endTagOpen)
+    <|> (char '?' >> bogusComment mempty)
+    <|> tagNameOpen
+    <|> other
+  where
+    other = do
+        return $ ContentChar '<'
+
+-- | /§8.2.4.7/: End tag open state
+endTagOpen :: Parser Token
+endTagOpen = tagNameClose
+
+-- | Equivalent to @inClass "\x09\x0a\x0c "@
+isWhitespace :: Char -> Bool
+isWhitespace '\x09' = True
+isWhitespace '\x0a' = True
+isWhitespace '\x0c' = True
+isWhitespace '\x0d' = True
+isWhitespace ' '    = True
+isWhitespace _      = False
+
+orC :: (Char -> Bool) -> (Char -> Bool) -> Char -> Bool
+orC f g c = f c || g c
+{-# INLINE orC #-}
+
+isC :: Char -> Char -> Bool
+isC = (==)
+{-# INLINE isC #-}
+
+-- | /§8.2.4.8/: Tag name state: the open case
+--
+-- deviation: no lower-casing, don't handle NULL characters
+tagNameOpen :: Parser Token
+tagNameOpen = do
+    tag <- tagName'
+    id $  (satisfy isWhitespace >> beforeAttrName tag [])
+      <|> (char '/' >> selfClosingStartTag tag [])
+      <|> (char '>' >> return (TagOpen tag []))
+
+-- | /§8.2.4.10/: Tag name state: close case
+tagNameClose :: Parser Token
+tagNameClose = do
+    tag <- tagName'
+    char '>' >> return (TagClose tag)
+
+-- | /§8.2.4.10/: Tag name state: common code
+--
+-- deviation: no lower-casing, don't handle NULL characters
+tagName' :: Parser Text
+tagName' = do
+    c <- peekChar'
+    guard $ isAsciiUpper c || isAsciiLower c
+    takeWhile $ not . (isWhitespace `orC` isC '/' `orC` isC '<' `orC` isC '>')
+
+-- | /§8.2.4.40/: Self-closing start tag state
+selfClosingStartTag :: TagName -> [Attr] -> Parser Token
+selfClosingStartTag tag attrs = do
+        (char '>' >> return (TagSelfClose tag attrs))
+    <|> (endOfInput >> return endOfFileToken)
+    <|> beforeAttrName tag attrs
+
+-- | /§8.2.4.32/: Before attribute name state
+--
+-- deviation: no lower-casing
+beforeAttrName :: TagName -> [Attr] -> Parser Token
+beforeAttrName tag attrs = do
+    skipWhile isWhitespace
+    id $  (char '/' >> selfClosingStartTag tag attrs)
+      <|> (char '>' >> return (TagOpen tag attrs))
+      -- <|> (char '\x00' >> attrName tag attrs) -- TODO: NULL
+      <|> attrName tag attrs
+
+-- | /§8.2.4.33/: Attribute name state
+attrName :: TagName -> [Attr] -> Parser Token
+attrName tag attrs = do
+    name <- takeWhile $ not . (isWhitespace `orC` isC '/' `orC` isC '=' `orC` isC '>')
+    id $  (endOfInput >> afterAttrName tag attrs name)
+      <|> (char '=' >> beforeAttrValue tag attrs name)
+      <|> try (do mc <- peekChar
+                  case mc of
+                    Just c | notNameChar c ->  afterAttrName tag attrs name
+                    _ -> empty)
+      -- <|> -- TODO: NULL
+  where notNameChar = isWhitespace `orC` isC '/' `orC` isC '>'
+
+-- | /§8.2.4.34/: After attribute name state
+afterAttrName :: TagName -> [Attr] -> AttrName -> Parser Token
+afterAttrName tag attrs name = do
+    skipWhile isWhitespace
+    id $  (char '/' >> selfClosingStartTag tag attrs)
+      <|> (char '=' >> beforeAttrValue tag attrs name)
+      <|> (char '>' >> return (TagOpen tag (Attr name T.empty : attrs)))
+      <|> (endOfInput >> return endOfFileToken)
+      <|> attrName tag (Attr name T.empty : attrs)  -- not exactly sure this is right
+
+-- | /§8.2.4.35/: Before attribute value state
+beforeAttrValue :: TagName -> [Attr] -> AttrName -> Parser Token
+beforeAttrValue tag attrs name = do
+    skipWhile isWhitespace
+    id $  (char '"' >> attrValueDQuoted tag attrs name)
+      <|> (char '\'' >> attrValueSQuoted tag attrs name)
+      <|> (char '>' >> return (TagOpen tag (Attr name T.empty : attrs)))
+      <|> attrValueUnquoted tag attrs name
+
+-- | /§8.2.4.36/: Attribute value (double-quoted) state
+attrValueDQuoted :: TagName -> [Attr] -> AttrName -> Parser Token
+attrValueDQuoted tag attrs name = do
+    value <- takeWhile (/= '"')
+    _ <- char '"'
+    afterAttrValueQuoted tag attrs name value
+
+-- | /§8.2.4.37/: Attribute value (single-quoted) state
+attrValueSQuoted :: TagName -> [Attr] -> AttrName -> Parser Token
+attrValueSQuoted tag attrs name = do
+    value <- takeWhile (/= '\'')
+    _ <- char '\''
+    afterAttrValueQuoted tag attrs name value
+
+-- | /§8.2.4.38/: Attribute value (unquoted) state
+attrValueUnquoted :: TagName -> [Attr] -> AttrName -> Parser Token
+attrValueUnquoted tag attrs name = do
+    value <- takeTill $ isWhitespace `orC` isC '>'
+    id $  (satisfy isWhitespace >> beforeAttrName tag attrs) -- unsure: don't emit?
+      <|> (char '>' >> return (TagOpen tag (Attr name value : attrs)))
+      <|> (endOfInput >> return endOfFileToken)
+
+-- | /§8.2.4.39/: After attribute value (quoted) state
+afterAttrValueQuoted :: TagName -> [Attr] -> AttrName -> AttrValue -> Parser Token
+afterAttrValueQuoted tag attrs name value =
+          (satisfy isWhitespace >> beforeAttrName tag attrs')
+      <|> (char '/' >> selfClosingStartTag tag attrs')
+      <|> (char '>' >> return (TagOpen tag attrs'))
+      <|> (endOfInput >> return endOfFileToken)
+  where attrs' = Attr name value : attrs
+
+-- | /§8.2.4.41/: Bogus comment state
+bogusComment :: Builder -> Parser Token
+bogusComment content = do
+        (char '>' >> return (Comment content))
+    <|> (endOfInput >> return (Comment content))
+    <|> (char '\x00' >> bogusComment (content <> "\xfffd"))
+    <|> (anyChar >>= \c -> bogusComment (content <> B.singleton c))
+
+-- | /§8.2.4.42/: Markup declaration open state
+markupDeclOpen :: Parser Token
+markupDeclOpen =
+        try comment_
+    <|> try docType
+    <|> bogusComment mempty
+  where
+    comment_ = char '-' >> char '-' >> commentStart
+    docType = do
+        -- switching this to asciiCI slowed things down by a factor of two
+        s <- take 7
+        guard $ T.toLower s == "doctype"
+        doctype
+
+-- | /§8.2.4.43/: Comment start state
+commentStart :: Parser Token
+commentStart = do
+          (char '-' >> commentStartDash)
+      <|> (char '>' >> return (Comment mempty))
+      <|> comment mempty
+
+-- | /§8.2.4.44/: Comment start dash state
+commentStartDash :: Parser Token
+commentStartDash =
+          (char '-' >> commentEnd mempty)
+      <|> (char '>' >> return (Comment mempty))
+      <|> (endOfInput >> return (Comment mempty))
+      <|> (comment (B.singleton '-'))
+
+-- | /§8.2.4.45/: Comment state
+comment :: Builder -> Parser Token
+comment content0 = do
+    content <- B.fromText <$> takeWhile (not . (isC '-' `orC` isC '\x00' `orC` isC '<'))
+    id $  (char '<' >> commentLessThan (content0 <> content <> "<"))
+      <|> (char '-' >> commentEndDash (content0 <> content))
+      <|> (char '\x00' >> comment (content0 <> content <> B.singleton '\xfffd'))
+      <|> (endOfInput >> return (Comment $ content0 <> content))
+
+-- | /§8.2.46/: Comment less-than sign state
+commentLessThan :: Builder -> Parser Token
+commentLessThan content =
+        (char '!' >> commentLessThanBang (content <> "!"))
+    <|> (char '<' >> commentLessThan (content <> "<"))
+    <|> comment content
+
+-- | /§8.2.47/: Comment less-than sign bang state
+commentLessThanBang :: Builder -> Parser Token
+commentLessThanBang content =
+        (char '-' >> commentLessThanBangDash content)
+    <|> comment content
+
+-- | /§8.2.48/: Comment less-than sign bang dash state
+commentLessThanBangDash :: Builder -> Parser Token
+commentLessThanBangDash content =
+        (char '-' >> commentLessThanBangDashDash content)
+    <|> commentEndDash content
+
+-- | /§8.2.49/: Comment less-than sign bang dash dash state
+commentLessThanBangDashDash :: Builder -> Parser Token
+commentLessThanBangDashDash content =
+        (char '>' >> comment content)
+    <|> (endOfInput >> comment content)
+    <|> commentEnd content
+
+-- | /§8.2.4.50/: Comment end dash state
+commentEndDash :: Builder -> Parser Token
+commentEndDash content = do
+        (char '-' >> commentEnd content)
+    <|> (endOfInput >> return (Comment content))
+    <|> (comment (content <> "-"))
+
+-- | /§8.2.4.51/: Comment end state
+commentEnd :: Builder -> Parser Token
+commentEnd content = do
+        (char '>' >> return (Comment content))
+    <|> (char '!' >> commentEndBang content)
+    <|> (char '-' >> commentEnd (content <> "-"))
+    <|> (endOfInput >> return (Comment content))
+    <|> (comment (content <> "--"))
+
+-- | /§8.2.4.52/: Comment end bang state
+commentEndBang :: Builder -> Parser Token
+commentEndBang content = do
+        (char '-' >> commentEndDash (content <> "--!"))
+    <|> (char '>' >> return (Comment content))
+    <|> (endOfInput >> return (Comment content))
+    <|> (comment (content <> "--!"))
+
+-- | /§8.2.4.53/: DOCTYPE state
+-- FIXME
+doctype :: Parser Token
+doctype = do
+    content <- takeTill (=='>')
+    _ <- char '>'
+    return $ Doctype content
+
+-- | Parse a lazy list of tokens from strict 'Text'.
+parseTokens :: Text -> [Token]
+parseTokens = unfoldr f
+  where
+    f :: Text -> Maybe (Token, Text)
+    f t
+      | T.null t = Nothing
+      | otherwise =
+        case parse token t of
+            Done rest tok -> Just (tok, rest)
+            Partial cont  ->
+                case cont mempty of
+                  Done rest tok -> Just (tok, rest)
+                  _             -> Nothing
+            _             -> Nothing
+
+-- | Parse a lazy list of tokens from lazy 'TL.Text'.
+parseTokensLazy :: TL.Text -> [Token]
+parseTokensLazy = unfoldr f
+  where
+    f :: TL.Text -> Maybe (Token, TL.Text)
+    f t
+      | TL.null t = Nothing
+      | otherwise =
+        case AL.parse token t of
+            AL.Done rest tok -> Just (tok, rest)
+            _                -> Nothing
+
+-- | See 'renderToken'.
+renderTokens :: [Token] -> TL.Text
+renderTokens = mconcat . fmap renderToken
+
+-- | (Somewhat) canonical string representation of 'Token'.
+renderToken :: Token -> TL.Text
+renderToken = TL.fromStrict . mconcat . \case
+    (TagOpen n [])         -> ["<", n, ">"]
+    (TagOpen n attrs)      -> ["<", n, " ", renderAttrs attrs, ">"]
+    (TagSelfClose n attrs) -> ["<", n, " ", renderAttrs attrs, " />"]
+    (TagClose n)           -> ["</", n, ">"]
+    (ContentChar c)        -> [T.singleton c]
+    (ContentText t)        -> [t]
+    (Comment builder)      -> ["<!--", TL.toStrict $ B.toLazyText builder, "-->"]
+    (Doctype t)            -> ["<!DOCTYPE", t, ">"]
+
+-- | See 'renderAttr'.
+renderAttrs :: [Attr] -> Text
+renderAttrs = T.unwords . fmap renderAttr . reverse
+
+-- | Does not escape quotation in attribute values!
+renderAttr :: Attr -> Text
+renderAttr (Attr k v) = mconcat [k, "=\"", v, "\""]
+
+-- | Meld neighoring 'ContentChar' and 'ContentText'
+-- constructors together and drops empty text elements.
+canonicalizeTokens :: [Token] -> [Token]
+canonicalizeTokens = filter (/= ContentText "") . meldTextTokens
+
+meldTextTokens :: [Token] -> [Token]
+meldTextTokens = concatTexts . fmap charToText
+  where
+    charToText (ContentChar c) = ContentText (T.singleton c)
+    charToText t = t
+
+    concatTexts = \case
+      (ContentText t : ContentText t' : ts) -> concatTexts $ ContentText (t <> t') : ts
+      (t : ts) -> t : concatTexts ts
+      [] -> []
diff --git a/src/Text/HTML/Parser/Entities.hs b/src/Text/HTML/Parser/Entities.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/Parser/Entities.hs
@@ -0,0 +1,2241 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | N.B. This file is generated by @gen_entities.py@. Do not edit.
+module Text.HTML.Parser.Entities (entities) where
+
+import Data.Text (Text)
+
+entities :: [(Text, Text)]
+entities = [
+  ("AEli", "\x00c6"),
+  ("AElig", "\x00c6"),
+  ("AM", "\x0026"),
+  ("AMP", "\x0026"),
+  ("Aacut", "\x00c1"),
+  ("Aacute", "\x00c1"),
+  ("Abreve", "\x0102"),
+  ("Acir", "\x00c2"),
+  ("Acirc", "\x00c2"),
+  ("Acy", "\x0410"),
+  ("Afr", "\x1d504"),
+  ("Agrav", "\x00c0"),
+  ("Agrave", "\x00c0"),
+  ("Alpha", "\x0391"),
+  ("Amacr", "\x0100"),
+  ("And", "\x2a53"),
+  ("Aogon", "\x0104"),
+  ("Aopf", "\x1d538"),
+  ("ApplyFunction", "\x2061"),
+  ("Arin", "\x00c5"),
+  ("Aring", "\x00c5"),
+  ("Ascr", "\x1d49c"),
+  ("Assign", "\x2254"),
+  ("Atild", "\x00c3"),
+  ("Atilde", "\x00c3"),
+  ("Aum", "\x00c4"),
+  ("Auml", "\x00c4"),
+  ("Backslash", "\x2216"),
+  ("Barv", "\x2ae7"),
+  ("Barwed", "\x2306"),
+  ("Bcy", "\x0411"),
+  ("Because", "\x2235"),
+  ("Bernoullis", "\x212c"),
+  ("Beta", "\x0392"),
+  ("Bfr", "\x1d505"),
+  ("Bopf", "\x1d539"),
+  ("Breve", "\x02d8"),
+  ("Bscr", "\x212c"),
+  ("Bumpeq", "\x224e"),
+  ("CHcy", "\x0427"),
+  ("COP", "\x00a9"),
+  ("COPY", "\x00a9"),
+  ("Cacute", "\x0106"),
+  ("Cap", "\x22d2"),
+  ("CapitalDifferentialD", "\x2145"),
+  ("Cayleys", "\x212d"),
+  ("Ccaron", "\x010c"),
+  ("Ccedi", "\x00c7"),
+  ("Ccedil", "\x00c7"),
+  ("Ccirc", "\x0108"),
+  ("Cconint", "\x2230"),
+  ("Cdot", "\x010a"),
+  ("Cedilla", "\x00b8"),
+  ("CenterDot", "\x00b7"),
+  ("Cfr", "\x212d"),
+  ("Chi", "\x03a7"),
+  ("CircleDot", "\x2299"),
+  ("CircleMinus", "\x2296"),
+  ("CirclePlus", "\x2295"),
+  ("CircleTimes", "\x2297"),
+  ("ClockwiseContourIntegral", "\x2232"),
+  ("CloseCurlyDoubleQuote", "\x201d"),
+  ("CloseCurlyQuote", "\x2019"),
+  ("Colon", "\x2237"),
+  ("Colone", "\x2a74"),
+  ("Congruent", "\x2261"),
+  ("Conint", "\x222f"),
+  ("ContourIntegral", "\x222e"),
+  ("Copf", "\x2102"),
+  ("Coproduct", "\x2210"),
+  ("CounterClockwiseContourIntegral", "\x2233"),
+  ("Cross", "\x2a2f"),
+  ("Cscr", "\x1d49e"),
+  ("Cup", "\x22d3"),
+  ("CupCap", "\x224d"),
+  ("DD", "\x2145"),
+  ("DDotrahd", "\x2911"),
+  ("DJcy", "\x0402"),
+  ("DScy", "\x0405"),
+  ("DZcy", "\x040f"),
+  ("Dagger", "\x2021"),
+  ("Darr", "\x21a1"),
+  ("Dashv", "\x2ae4"),
+  ("Dcaron", "\x010e"),
+  ("Dcy", "\x0414"),
+  ("Del", "\x2207"),
+  ("Delta", "\x0394"),
+  ("Dfr", "\x1d507"),
+  ("DiacriticalAcute", "\x00b4"),
+  ("DiacriticalDot", "\x02d9"),
+  ("DiacriticalDoubleAcute", "\x02dd"),
+  ("DiacriticalGrave", "\x0060"),
+  ("DiacriticalTilde", "\x02dc"),
+  ("Diamond", "\x22c4"),
+  ("DifferentialD", "\x2146"),
+  ("Dopf", "\x1d53b"),
+  ("Dot", "\x00a8"),
+  ("DotDot", "\x20dc"),
+  ("DotEqual", "\x2250"),
+  ("DoubleContourIntegral", "\x222f"),
+  ("DoubleDot", "\x00a8"),
+  ("DoubleDownArrow", "\x21d3"),
+  ("DoubleLeftArrow", "\x21d0"),
+  ("DoubleLeftRightArrow", "\x21d4"),
+  ("DoubleLeftTee", "\x2ae4"),
+  ("DoubleLongLeftArrow", "\x27f8"),
+  ("DoubleLongLeftRightArrow", "\x27fa"),
+  ("DoubleLongRightArrow", "\x27f9"),
+  ("DoubleRightArrow", "\x21d2"),
+  ("DoubleRightTee", "\x22a8"),
+  ("DoubleUpArrow", "\x21d1"),
+  ("DoubleUpDownArrow", "\x21d5"),
+  ("DoubleVerticalBar", "\x2225"),
+  ("DownArrow", "\x2193"),
+  ("DownArrowBar", "\x2913"),
+  ("DownArrowUpArrow", "\x21f5"),
+  ("DownBreve", "\x0311"),
+  ("DownLeftRightVector", "\x2950"),
+  ("DownLeftTeeVector", "\x295e"),
+  ("DownLeftVector", "\x21bd"),
+  ("DownLeftVectorBar", "\x2956"),
+  ("DownRightTeeVector", "\x295f"),
+  ("DownRightVector", "\x21c1"),
+  ("DownRightVectorBar", "\x2957"),
+  ("DownTee", "\x22a4"),
+  ("DownTeeArrow", "\x21a7"),
+  ("Downarrow", "\x21d3"),
+  ("Dscr", "\x1d49f"),
+  ("Dstrok", "\x0110"),
+  ("ENG", "\x014a"),
+  ("ET", "\x00d0"),
+  ("ETH", "\x00d0"),
+  ("Eacut", "\x00c9"),
+  ("Eacute", "\x00c9"),
+  ("Ecaron", "\x011a"),
+  ("Ecir", "\x00ca"),
+  ("Ecirc", "\x00ca"),
+  ("Ecy", "\x042d"),
+  ("Edot", "\x0116"),
+  ("Efr", "\x1d508"),
+  ("Egrav", "\x00c8"),
+  ("Egrave", "\x00c8"),
+  ("Element", "\x2208"),
+  ("Emacr", "\x0112"),
+  ("EmptySmallSquare", "\x25fb"),
+  ("EmptyVerySmallSquare", "\x25ab"),
+  ("Eogon", "\x0118"),
+  ("Eopf", "\x1d53c"),
+  ("Epsilon", "\x0395"),
+  ("Equal", "\x2a75"),
+  ("EqualTilde", "\x2242"),
+  ("Equilibrium", "\x21cc"),
+  ("Escr", "\x2130"),
+  ("Esim", "\x2a73"),
+  ("Eta", "\x0397"),
+  ("Eum", "\x00cb"),
+  ("Euml", "\x00cb"),
+  ("Exists", "\x2203"),
+  ("ExponentialE", "\x2147"),
+  ("Fcy", "\x0424"),
+  ("Ffr", "\x1d509"),
+  ("FilledSmallSquare", "\x25fc"),
+  ("FilledVerySmallSquare", "\x25aa"),
+  ("Fopf", "\x1d53d"),
+  ("ForAll", "\x2200"),
+  ("Fouriertrf", "\x2131"),
+  ("Fscr", "\x2131"),
+  ("GJcy", "\x0403"),
+  ("G", "\x003e"),
+  ("GT", "\x003e"),
+  ("Gamma", "\x0393"),
+  ("Gammad", "\x03dc"),
+  ("Gbreve", "\x011e"),
+  ("Gcedil", "\x0122"),
+  ("Gcirc", "\x011c"),
+  ("Gcy", "\x0413"),
+  ("Gdot", "\x0120"),
+  ("Gfr", "\x1d50a"),
+  ("Gg", "\x22d9"),
+  ("Gopf", "\x1d53e"),
+  ("GreaterEqual", "\x2265"),
+  ("GreaterEqualLess", "\x22db"),
+  ("GreaterFullEqual", "\x2267"),
+  ("GreaterGreater", "\x2aa2"),
+  ("GreaterLess", "\x2277"),
+  ("GreaterSlantEqual", "\x2a7e"),
+  ("GreaterTilde", "\x2273"),
+  ("Gscr", "\x1d4a2"),
+  ("Gt", "\x226b"),
+  ("HARDcy", "\x042a"),
+  ("Hacek", "\x02c7"),
+  ("Hat", "\x005e"),
+  ("Hcirc", "\x0124"),
+  ("Hfr", "\x210c"),
+  ("HilbertSpace", "\x210b"),
+  ("Hopf", "\x210d"),
+  ("HorizontalLine", "\x2500"),
+  ("Hscr", "\x210b"),
+  ("Hstrok", "\x0126"),
+  ("HumpDownHump", "\x224e"),
+  ("HumpEqual", "\x224f"),
+  ("IEcy", "\x0415"),
+  ("IJlig", "\x0132"),
+  ("IOcy", "\x0401"),
+  ("Iacut", "\x00cd"),
+  ("Iacute", "\x00cd"),
+  ("Icir", "\x00ce"),
+  ("Icirc", "\x00ce"),
+  ("Icy", "\x0418"),
+  ("Idot", "\x0130"),
+  ("Ifr", "\x2111"),
+  ("Igrav", "\x00cc"),
+  ("Igrave", "\x00cc"),
+  ("Im", "\x2111"),
+  ("Imacr", "\x012a"),
+  ("ImaginaryI", "\x2148"),
+  ("Implies", "\x21d2"),
+  ("Int", "\x222c"),
+  ("Integral", "\x222b"),
+  ("Intersection", "\x22c2"),
+  ("InvisibleComma", "\x2063"),
+  ("InvisibleTimes", "\x2062"),
+  ("Iogon", "\x012e"),
+  ("Iopf", "\x1d540"),
+  ("Iota", "\x0399"),
+  ("Iscr", "\x2110"),
+  ("Itilde", "\x0128"),
+  ("Iukcy", "\x0406"),
+  ("Ium", "\x00cf"),
+  ("Iuml", "\x00cf"),
+  ("Jcirc", "\x0134"),
+  ("Jcy", "\x0419"),
+  ("Jfr", "\x1d50d"),
+  ("Jopf", "\x1d541"),
+  ("Jscr", "\x1d4a5"),
+  ("Jsercy", "\x0408"),
+  ("Jukcy", "\x0404"),
+  ("KHcy", "\x0425"),
+  ("KJcy", "\x040c"),
+  ("Kappa", "\x039a"),
+  ("Kcedil", "\x0136"),
+  ("Kcy", "\x041a"),
+  ("Kfr", "\x1d50e"),
+  ("Kopf", "\x1d542"),
+  ("Kscr", "\x1d4a6"),
+  ("LJcy", "\x0409"),
+  ("L", "\x003c"),
+  ("LT", "\x003c"),
+  ("Lacute", "\x0139"),
+  ("Lambda", "\x039b"),
+  ("Lang", "\x27ea"),
+  ("Laplacetrf", "\x2112"),
+  ("Larr", "\x219e"),
+  ("Lcaron", "\x013d"),
+  ("Lcedil", "\x013b"),
+  ("Lcy", "\x041b"),
+  ("LeftAngleBracket", "\x27e8"),
+  ("LeftArrow", "\x2190"),
+  ("LeftArrowBar", "\x21e4"),
+  ("LeftArrowRightArrow", "\x21c6"),
+  ("LeftCeiling", "\x2308"),
+  ("LeftDoubleBracket", "\x27e6"),
+  ("LeftDownTeeVector", "\x2961"),
+  ("LeftDownVector", "\x21c3"),
+  ("LeftDownVectorBar", "\x2959"),
+  ("LeftFloor", "\x230a"),
+  ("LeftRightArrow", "\x2194"),
+  ("LeftRightVector", "\x294e"),
+  ("LeftTee", "\x22a3"),
+  ("LeftTeeArrow", "\x21a4"),
+  ("LeftTeeVector", "\x295a"),
+  ("LeftTriangle", "\x22b2"),
+  ("LeftTriangleBar", "\x29cf"),
+  ("LeftTriangleEqual", "\x22b4"),
+  ("LeftUpDownVector", "\x2951"),
+  ("LeftUpTeeVector", "\x2960"),
+  ("LeftUpVector", "\x21bf"),
+  ("LeftUpVectorBar", "\x2958"),
+  ("LeftVector", "\x21bc"),
+  ("LeftVectorBar", "\x2952"),
+  ("Leftarrow", "\x21d0"),
+  ("Leftrightarrow", "\x21d4"),
+  ("LessEqualGreater", "\x22da"),
+  ("LessFullEqual", "\x2266"),
+  ("LessGreater", "\x2276"),
+  ("LessLess", "\x2aa1"),
+  ("LessSlantEqual", "\x2a7d"),
+  ("LessTilde", "\x2272"),
+  ("Lfr", "\x1d50f"),
+  ("Ll", "\x22d8"),
+  ("Lleftarrow", "\x21da"),
+  ("Lmidot", "\x013f"),
+  ("LongLeftArrow", "\x27f5"),
+  ("LongLeftRightArrow", "\x27f7"),
+  ("LongRightArrow", "\x27f6"),
+  ("Longleftarrow", "\x27f8"),
+  ("Longleftrightarrow", "\x27fa"),
+  ("Longrightarrow", "\x27f9"),
+  ("Lopf", "\x1d543"),
+  ("LowerLeftArrow", "\x2199"),
+  ("LowerRightArrow", "\x2198"),
+  ("Lscr", "\x2112"),
+  ("Lsh", "\x21b0"),
+  ("Lstrok", "\x0141"),
+  ("Lt", "\x226a"),
+  ("Map", "\x2905"),
+  ("Mcy", "\x041c"),
+  ("MediumSpace", "\x205f"),
+  ("Mellintrf", "\x2133"),
+  ("Mfr", "\x1d510"),
+  ("MinusPlus", "\x2213"),
+  ("Mopf", "\x1d544"),
+  ("Mscr", "\x2133"),
+  ("Mu", "\x039c"),
+  ("NJcy", "\x040a"),
+  ("Nacute", "\x0143"),
+  ("Ncaron", "\x0147"),
+  ("Ncedil", "\x0145"),
+  ("Ncy", "\x041d"),
+  ("NegativeMediumSpace", "\x200b"),
+  ("NegativeThickSpace", "\x200b"),
+  ("NegativeThinSpace", "\x200b"),
+  ("NegativeVeryThinSpace", "\x200b"),
+  ("NestedGreaterGreater", "\x226b"),
+  ("NestedLessLess", "\x226a"),
+  ("NewLine", "\x000a"),
+  ("Nfr", "\x1d511"),
+  ("NoBreak", "\x2060"),
+  ("NonBreakingSpace", "\x00a0"),
+  ("Nopf", "\x2115"),
+  ("Not", "\x2aec"),
+  ("NotCongruent", "\x2262"),
+  ("NotCupCap", "\x226d"),
+  ("NotDoubleVerticalBar", "\x2226"),
+  ("NotElement", "\x2209"),
+  ("NotEqual", "\x2260"),
+  ("NotEqualTilde", "\x2242\x0338"),
+  ("NotExists", "\x2204"),
+  ("NotGreater", "\x226f"),
+  ("NotGreaterEqual", "\x2271"),
+  ("NotGreaterFullEqual", "\x2267\x0338"),
+  ("NotGreaterGreater", "\x226b\x0338"),
+  ("NotGreaterLess", "\x2279"),
+  ("NotGreaterSlantEqual", "\x2a7e\x0338"),
+  ("NotGreaterTilde", "\x2275"),
+  ("NotHumpDownHump", "\x224e\x0338"),
+  ("NotHumpEqual", "\x224f\x0338"),
+  ("NotLeftTriangle", "\x22ea"),
+  ("NotLeftTriangleBar", "\x29cf\x0338"),
+  ("NotLeftTriangleEqual", "\x22ec"),
+  ("NotLess", "\x226e"),
+  ("NotLessEqual", "\x2270"),
+  ("NotLessGreater", "\x2278"),
+  ("NotLessLess", "\x226a\x0338"),
+  ("NotLessSlantEqual", "\x2a7d\x0338"),
+  ("NotLessTilde", "\x2274"),
+  ("NotNestedGreaterGreater", "\x2aa2\x0338"),
+  ("NotNestedLessLess", "\x2aa1\x0338"),
+  ("NotPrecedes", "\x2280"),
+  ("NotPrecedesEqual", "\x2aaf\x0338"),
+  ("NotPrecedesSlantEqual", "\x22e0"),
+  ("NotReverseElement", "\x220c"),
+  ("NotRightTriangle", "\x22eb"),
+  ("NotRightTriangleBar", "\x29d0\x0338"),
+  ("NotRightTriangleEqual", "\x22ed"),
+  ("NotSquareSubset", "\x228f\x0338"),
+  ("NotSquareSubsetEqual", "\x22e2"),
+  ("NotSquareSuperset", "\x2290\x0338"),
+  ("NotSquareSupersetEqual", "\x22e3"),
+  ("NotSubset", "\x2282\x20d2"),
+  ("NotSubsetEqual", "\x2288"),
+  ("NotSucceeds", "\x2281"),
+  ("NotSucceedsEqual", "\x2ab0\x0338"),
+  ("NotSucceedsSlantEqual", "\x22e1"),
+  ("NotSucceedsTilde", "\x227f\x0338"),
+  ("NotSuperset", "\x2283\x20d2"),
+  ("NotSupersetEqual", "\x2289"),
+  ("NotTilde", "\x2241"),
+  ("NotTildeEqual", "\x2244"),
+  ("NotTildeFullEqual", "\x2247"),
+  ("NotTildeTilde", "\x2249"),
+  ("NotVerticalBar", "\x2224"),
+  ("Nscr", "\x1d4a9"),
+  ("Ntild", "\x00d1"),
+  ("Ntilde", "\x00d1"),
+  ("Nu", "\x039d"),
+  ("OElig", "\x0152"),
+  ("Oacut", "\x00d3"),
+  ("Oacute", "\x00d3"),
+  ("Ocir", "\x00d4"),
+  ("Ocirc", "\x00d4"),
+  ("Ocy", "\x041e"),
+  ("Odblac", "\x0150"),
+  ("Ofr", "\x1d512"),
+  ("Ograv", "\x00d2"),
+  ("Ograve", "\x00d2"),
+  ("Omacr", "\x014c"),
+  ("Omega", "\x03a9"),
+  ("Omicron", "\x039f"),
+  ("Oopf", "\x1d546"),
+  ("OpenCurlyDoubleQuote", "\x201c"),
+  ("OpenCurlyQuote", "\x2018"),
+  ("Or", "\x2a54"),
+  ("Oscr", "\x1d4aa"),
+  ("Oslas", "\x00d8"),
+  ("Oslash", "\x00d8"),
+  ("Otild", "\x00d5"),
+  ("Otilde", "\x00d5"),
+  ("Otimes", "\x2a37"),
+  ("Oum", "\x00d6"),
+  ("Ouml", "\x00d6"),
+  ("OverBar", "\x203e"),
+  ("OverBrace", "\x23de"),
+  ("OverBracket", "\x23b4"),
+  ("OverParenthesis", "\x23dc"),
+  ("PartialD", "\x2202"),
+  ("Pcy", "\x041f"),
+  ("Pfr", "\x1d513"),
+  ("Phi", "\x03a6"),
+  ("Pi", "\x03a0"),
+  ("PlusMinus", "\x00b1"),
+  ("Poincareplane", "\x210c"),
+  ("Popf", "\x2119"),
+  ("Pr", "\x2abb"),
+  ("Precedes", "\x227a"),
+  ("PrecedesEqual", "\x2aaf"),
+  ("PrecedesSlantEqual", "\x227c"),
+  ("PrecedesTilde", "\x227e"),
+  ("Prime", "\x2033"),
+  ("Product", "\x220f"),
+  ("Proportion", "\x2237"),
+  ("Proportional", "\x221d"),
+  ("Pscr", "\x1d4ab"),
+  ("Psi", "\x03a8"),
+  ("QUO", "\x0022"),
+  ("QUOT", "\x0022"),
+  ("Qfr", "\x1d514"),
+  ("Qopf", "\x211a"),
+  ("Qscr", "\x1d4ac"),
+  ("RBarr", "\x2910"),
+  ("RE", "\x00ae"),
+  ("REG", "\x00ae"),
+  ("Racute", "\x0154"),
+  ("Rang", "\x27eb"),
+  ("Rarr", "\x21a0"),
+  ("Rarrtl", "\x2916"),
+  ("Rcaron", "\x0158"),
+  ("Rcedil", "\x0156"),
+  ("Rcy", "\x0420"),
+  ("Re", "\x211c"),
+  ("ReverseElement", "\x220b"),
+  ("ReverseEquilibrium", "\x21cb"),
+  ("ReverseUpEquilibrium", "\x296f"),
+  ("Rfr", "\x211c"),
+  ("Rho", "\x03a1"),
+  ("RightAngleBracket", "\x27e9"),
+  ("RightArrow", "\x2192"),
+  ("RightArrowBar", "\x21e5"),
+  ("RightArrowLeftArrow", "\x21c4"),
+  ("RightCeiling", "\x2309"),
+  ("RightDoubleBracket", "\x27e7"),
+  ("RightDownTeeVector", "\x295d"),
+  ("RightDownVector", "\x21c2"),
+  ("RightDownVectorBar", "\x2955"),
+  ("RightFloor", "\x230b"),
+  ("RightTee", "\x22a2"),
+  ("RightTeeArrow", "\x21a6"),
+  ("RightTeeVector", "\x295b"),
+  ("RightTriangle", "\x22b3"),
+  ("RightTriangleBar", "\x29d0"),
+  ("RightTriangleEqual", "\x22b5"),
+  ("RightUpDownVector", "\x294f"),
+  ("RightUpTeeVector", "\x295c"),
+  ("RightUpVector", "\x21be"),
+  ("RightUpVectorBar", "\x2954"),
+  ("RightVector", "\x21c0"),
+  ("RightVectorBar", "\x2953"),
+  ("Rightarrow", "\x21d2"),
+  ("Ropf", "\x211d"),
+  ("RoundImplies", "\x2970"),
+  ("Rrightarrow", "\x21db"),
+  ("Rscr", "\x211b"),
+  ("Rsh", "\x21b1"),
+  ("RuleDelayed", "\x29f4"),
+  ("SHCHcy", "\x0429"),
+  ("SHcy", "\x0428"),
+  ("SOFTcy", "\x042c"),
+  ("Sacute", "\x015a"),
+  ("Sc", "\x2abc"),
+  ("Scaron", "\x0160"),
+  ("Scedil", "\x015e"),
+  ("Scirc", "\x015c"),
+  ("Scy", "\x0421"),
+  ("Sfr", "\x1d516"),
+  ("ShortDownArrow", "\x2193"),
+  ("ShortLeftArrow", "\x2190"),
+  ("ShortRightArrow", "\x2192"),
+  ("ShortUpArrow", "\x2191"),
+  ("Sigma", "\x03a3"),
+  ("SmallCircle", "\x2218"),
+  ("Sopf", "\x1d54a"),
+  ("Sqrt", "\x221a"),
+  ("Square", "\x25a1"),
+  ("SquareIntersection", "\x2293"),
+  ("SquareSubset", "\x228f"),
+  ("SquareSubsetEqual", "\x2291"),
+  ("SquareSuperset", "\x2290"),
+  ("SquareSupersetEqual", "\x2292"),
+  ("SquareUnion", "\x2294"),
+  ("Sscr", "\x1d4ae"),
+  ("Star", "\x22c6"),
+  ("Sub", "\x22d0"),
+  ("Subset", "\x22d0"),
+  ("SubsetEqual", "\x2286"),
+  ("Succeeds", "\x227b"),
+  ("SucceedsEqual", "\x2ab0"),
+  ("SucceedsSlantEqual", "\x227d"),
+  ("SucceedsTilde", "\x227f"),
+  ("SuchThat", "\x220b"),
+  ("Sum", "\x2211"),
+  ("Sup", "\x22d1"),
+  ("Superset", "\x2283"),
+  ("SupersetEqual", "\x2287"),
+  ("Supset", "\x22d1"),
+  ("THOR", "\x00de"),
+  ("THORN", "\x00de"),
+  ("TRADE", "\x2122"),
+  ("TSHcy", "\x040b"),
+  ("TScy", "\x0426"),
+  ("Tab", "\x0009"),
+  ("Tau", "\x03a4"),
+  ("Tcaron", "\x0164"),
+  ("Tcedil", "\x0162"),
+  ("Tcy", "\x0422"),
+  ("Tfr", "\x1d517"),
+  ("Therefore", "\x2234"),
+  ("Theta", "\x0398"),
+  ("ThickSpace", "\x205f\x200a"),
+  ("ThinSpace", "\x2009"),
+  ("Tilde", "\x223c"),
+  ("TildeEqual", "\x2243"),
+  ("TildeFullEqual", "\x2245"),
+  ("TildeTilde", "\x2248"),
+  ("Topf", "\x1d54b"),
+  ("TripleDot", "\x20db"),
+  ("Tscr", "\x1d4af"),
+  ("Tstrok", "\x0166"),
+  ("Uacut", "\x00da"),
+  ("Uacute", "\x00da"),
+  ("Uarr", "\x219f"),
+  ("Uarrocir", "\x2949"),
+  ("Ubrcy", "\x040e"),
+  ("Ubreve", "\x016c"),
+  ("Ucir", "\x00db"),
+  ("Ucirc", "\x00db"),
+  ("Ucy", "\x0423"),
+  ("Udblac", "\x0170"),
+  ("Ufr", "\x1d518"),
+  ("Ugrav", "\x00d9"),
+  ("Ugrave", "\x00d9"),
+  ("Umacr", "\x016a"),
+  ("UnderBar", "\x005f"),
+  ("UnderBrace", "\x23df"),
+  ("UnderBracket", "\x23b5"),
+  ("UnderParenthesis", "\x23dd"),
+  ("Union", "\x22c3"),
+  ("UnionPlus", "\x228e"),
+  ("Uogon", "\x0172"),
+  ("Uopf", "\x1d54c"),
+  ("UpArrow", "\x2191"),
+  ("UpArrowBar", "\x2912"),
+  ("UpArrowDownArrow", "\x21c5"),
+  ("UpDownArrow", "\x2195"),
+  ("UpEquilibrium", "\x296e"),
+  ("UpTee", "\x22a5"),
+  ("UpTeeArrow", "\x21a5"),
+  ("Uparrow", "\x21d1"),
+  ("Updownarrow", "\x21d5"),
+  ("UpperLeftArrow", "\x2196"),
+  ("UpperRightArrow", "\x2197"),
+  ("Upsi", "\x03d2"),
+  ("Upsilon", "\x03a5"),
+  ("Uring", "\x016e"),
+  ("Uscr", "\x1d4b0"),
+  ("Utilde", "\x0168"),
+  ("Uum", "\x00dc"),
+  ("Uuml", "\x00dc"),
+  ("VDash", "\x22ab"),
+  ("Vbar", "\x2aeb"),
+  ("Vcy", "\x0412"),
+  ("Vdash", "\x22a9"),
+  ("Vdashl", "\x2ae6"),
+  ("Vee", "\x22c1"),
+  ("Verbar", "\x2016"),
+  ("Vert", "\x2016"),
+  ("VerticalBar", "\x2223"),
+  ("VerticalLine", "\x007c"),
+  ("VerticalSeparator", "\x2758"),
+  ("VerticalTilde", "\x2240"),
+  ("VeryThinSpace", "\x200a"),
+  ("Vfr", "\x1d519"),
+  ("Vopf", "\x1d54d"),
+  ("Vscr", "\x1d4b1"),
+  ("Vvdash", "\x22aa"),
+  ("Wcirc", "\x0174"),
+  ("Wedge", "\x22c0"),
+  ("Wfr", "\x1d51a"),
+  ("Wopf", "\x1d54e"),
+  ("Wscr", "\x1d4b2"),
+  ("Xfr", "\x1d51b"),
+  ("Xi", "\x039e"),
+  ("Xopf", "\x1d54f"),
+  ("Xscr", "\x1d4b3"),
+  ("YAcy", "\x042f"),
+  ("YIcy", "\x0407"),
+  ("YUcy", "\x042e"),
+  ("Yacut", "\x00dd"),
+  ("Yacute", "\x00dd"),
+  ("Ycirc", "\x0176"),
+  ("Ycy", "\x042b"),
+  ("Yfr", "\x1d51c"),
+  ("Yopf", "\x1d550"),
+  ("Yscr", "\x1d4b4"),
+  ("Yuml", "\x0178"),
+  ("ZHcy", "\x0416"),
+  ("Zacute", "\x0179"),
+  ("Zcaron", "\x017d"),
+  ("Zcy", "\x0417"),
+  ("Zdot", "\x017b"),
+  ("ZeroWidthSpace", "\x200b"),
+  ("Zeta", "\x0396"),
+  ("Zfr", "\x2128"),
+  ("Zopf", "\x2124"),
+  ("Zscr", "\x1d4b5"),
+  ("aacut", "\x00e1"),
+  ("aacute", "\x00e1"),
+  ("abreve", "\x0103"),
+  ("ac", "\x223e"),
+  ("acE", "\x223e\x0333"),
+  ("acd", "\x223f"),
+  ("acir", "\x00e2"),
+  ("acirc", "\x00e2"),
+  ("acut", "\x00b4"),
+  ("acute", "\x00b4"),
+  ("acy", "\x0430"),
+  ("aeli", "\x00e6"),
+  ("aelig", "\x00e6"),
+  ("af", "\x2061"),
+  ("afr", "\x1d51e"),
+  ("agrav", "\x00e0"),
+  ("agrave", "\x00e0"),
+  ("alefsym", "\x2135"),
+  ("aleph", "\x2135"),
+  ("alpha", "\x03b1"),
+  ("amacr", "\x0101"),
+  ("amalg", "\x2a3f"),
+  ("am", "\x0026"),
+  ("amp", "\x0026"),
+  ("and", "\x2227"),
+  ("andand", "\x2a55"),
+  ("andd", "\x2a5c"),
+  ("andslope", "\x2a58"),
+  ("andv", "\x2a5a"),
+  ("ang", "\x2220"),
+  ("ange", "\x29a4"),
+  ("angle", "\x2220"),
+  ("angmsd", "\x2221"),
+  ("angmsdaa", "\x29a8"),
+  ("angmsdab", "\x29a9"),
+  ("angmsdac", "\x29aa"),
+  ("angmsdad", "\x29ab"),
+  ("angmsdae", "\x29ac"),
+  ("angmsdaf", "\x29ad"),
+  ("angmsdag", "\x29ae"),
+  ("angmsdah", "\x29af"),
+  ("angrt", "\x221f"),
+  ("angrtvb", "\x22be"),
+  ("angrtvbd", "\x299d"),
+  ("angsph", "\x2222"),
+  ("angst", "\x00c5"),
+  ("angzarr", "\x237c"),
+  ("aogon", "\x0105"),
+  ("aopf", "\x1d552"),
+  ("ap", "\x2248"),
+  ("apE", "\x2a70"),
+  ("apacir", "\x2a6f"),
+  ("ape", "\x224a"),
+  ("apid", "\x224b"),
+  ("apos", "\x0027"),
+  ("approx", "\x2248"),
+  ("approxeq", "\x224a"),
+  ("arin", "\x00e5"),
+  ("aring", "\x00e5"),
+  ("ascr", "\x1d4b6"),
+  ("ast", "\x002a"),
+  ("asymp", "\x2248"),
+  ("asympeq", "\x224d"),
+  ("atild", "\x00e3"),
+  ("atilde", "\x00e3"),
+  ("aum", "\x00e4"),
+  ("auml", "\x00e4"),
+  ("awconint", "\x2233"),
+  ("awint", "\x2a11"),
+  ("bNot", "\x2aed"),
+  ("backcong", "\x224c"),
+  ("backepsilon", "\x03f6"),
+  ("backprime", "\x2035"),
+  ("backsim", "\x223d"),
+  ("backsimeq", "\x22cd"),
+  ("barvee", "\x22bd"),
+  ("barwed", "\x2305"),
+  ("barwedge", "\x2305"),
+  ("bbrk", "\x23b5"),
+  ("bbrktbrk", "\x23b6"),
+  ("bcong", "\x224c"),
+  ("bcy", "\x0431"),
+  ("bdquo", "\x201e"),
+  ("becaus", "\x2235"),
+  ("because", "\x2235"),
+  ("bemptyv", "\x29b0"),
+  ("bepsi", "\x03f6"),
+  ("bernou", "\x212c"),
+  ("beta", "\x03b2"),
+  ("beth", "\x2136"),
+  ("between", "\x226c"),
+  ("bfr", "\x1d51f"),
+  ("bigcap", "\x22c2"),
+  ("bigcirc", "\x25ef"),
+  ("bigcup", "\x22c3"),
+  ("bigodot", "\x2a00"),
+  ("bigoplus", "\x2a01"),
+  ("bigotimes", "\x2a02"),
+  ("bigsqcup", "\x2a06"),
+  ("bigstar", "\x2605"),
+  ("bigtriangledown", "\x25bd"),
+  ("bigtriangleup", "\x25b3"),
+  ("biguplus", "\x2a04"),
+  ("bigvee", "\x22c1"),
+  ("bigwedge", "\x22c0"),
+  ("bkarow", "\x290d"),
+  ("blacklozenge", "\x29eb"),
+  ("blacksquare", "\x25aa"),
+  ("blacktriangle", "\x25b4"),
+  ("blacktriangledown", "\x25be"),
+  ("blacktriangleleft", "\x25c2"),
+  ("blacktriangleright", "\x25b8"),
+  ("blank", "\x2423"),
+  ("blk12", "\x2592"),
+  ("blk14", "\x2591"),
+  ("blk34", "\x2593"),
+  ("block", "\x2588"),
+  ("bne", "\x003d\x20e5"),
+  ("bnequiv", "\x2261\x20e5"),
+  ("bnot", "\x2310"),
+  ("bopf", "\x1d553"),
+  ("bot", "\x22a5"),
+  ("bottom", "\x22a5"),
+  ("bowtie", "\x22c8"),
+  ("boxDL", "\x2557"),
+  ("boxDR", "\x2554"),
+  ("boxDl", "\x2556"),
+  ("boxDr", "\x2553"),
+  ("boxH", "\x2550"),
+  ("boxHD", "\x2566"),
+  ("boxHU", "\x2569"),
+  ("boxHd", "\x2564"),
+  ("boxHu", "\x2567"),
+  ("boxUL", "\x255d"),
+  ("boxUR", "\x255a"),
+  ("boxUl", "\x255c"),
+  ("boxUr", "\x2559"),
+  ("boxV", "\x2551"),
+  ("boxVH", "\x256c"),
+  ("boxVL", "\x2563"),
+  ("boxVR", "\x2560"),
+  ("boxVh", "\x256b"),
+  ("boxVl", "\x2562"),
+  ("boxVr", "\x255f"),
+  ("boxbox", "\x29c9"),
+  ("boxdL", "\x2555"),
+  ("boxdR", "\x2552"),
+  ("boxdl", "\x2510"),
+  ("boxdr", "\x250c"),
+  ("boxh", "\x2500"),
+  ("boxhD", "\x2565"),
+  ("boxhU", "\x2568"),
+  ("boxhd", "\x252c"),
+  ("boxhu", "\x2534"),
+  ("boxminus", "\x229f"),
+  ("boxplus", "\x229e"),
+  ("boxtimes", "\x22a0"),
+  ("boxuL", "\x255b"),
+  ("boxuR", "\x2558"),
+  ("boxul", "\x2518"),
+  ("boxur", "\x2514"),
+  ("boxv", "\x2502"),
+  ("boxvH", "\x256a"),
+  ("boxvL", "\x2561"),
+  ("boxvR", "\x255e"),
+  ("boxvh", "\x253c"),
+  ("boxvl", "\x2524"),
+  ("boxvr", "\x251c"),
+  ("bprime", "\x2035"),
+  ("breve", "\x02d8"),
+  ("brvba", "\x00a6"),
+  ("brvbar", "\x00a6"),
+  ("bscr", "\x1d4b7"),
+  ("bsemi", "\x204f"),
+  ("bsim", "\x223d"),
+  ("bsime", "\x22cd"),
+  ("bsol", "\x005c"),
+  ("bsolb", "\x29c5"),
+  ("bsolhsub", "\x27c8"),
+  ("bull", "\x2022"),
+  ("bullet", "\x2022"),
+  ("bump", "\x224e"),
+  ("bumpE", "\x2aae"),
+  ("bumpe", "\x224f"),
+  ("bumpeq", "\x224f"),
+  ("cacute", "\x0107"),
+  ("cap", "\x2229"),
+  ("capand", "\x2a44"),
+  ("capbrcup", "\x2a49"),
+  ("capcap", "\x2a4b"),
+  ("capcup", "\x2a47"),
+  ("capdot", "\x2a40"),
+  ("caps", "\x2229\xfe00"),
+  ("caret", "\x2041"),
+  ("caron", "\x02c7"),
+  ("ccaps", "\x2a4d"),
+  ("ccaron", "\x010d"),
+  ("ccedi", "\x00e7"),
+  ("ccedil", "\x00e7"),
+  ("ccirc", "\x0109"),
+  ("ccups", "\x2a4c"),
+  ("ccupssm", "\x2a50"),
+  ("cdot", "\x010b"),
+  ("cedi", "\x00b8"),
+  ("cedil", "\x00b8"),
+  ("cemptyv", "\x29b2"),
+  ("cen", "\x00a2"),
+  ("cent", "\x00a2"),
+  ("centerdot", "\x00b7"),
+  ("cfr", "\x1d520"),
+  ("chcy", "\x0447"),
+  ("check", "\x2713"),
+  ("checkmark", "\x2713"),
+  ("chi", "\x03c7"),
+  ("cir", "\x25cb"),
+  ("cirE", "\x29c3"),
+  ("circ", "\x02c6"),
+  ("circeq", "\x2257"),
+  ("circlearrowleft", "\x21ba"),
+  ("circlearrowright", "\x21bb"),
+  ("circledR", "\x00ae"),
+  ("circledS", "\x24c8"),
+  ("circledast", "\x229b"),
+  ("circledcirc", "\x229a"),
+  ("circleddash", "\x229d"),
+  ("cire", "\x2257"),
+  ("cirfnint", "\x2a10"),
+  ("cirmid", "\x2aef"),
+  ("cirscir", "\x29c2"),
+  ("clubs", "\x2663"),
+  ("clubsuit", "\x2663"),
+  ("colon", "\x003a"),
+  ("colone", "\x2254"),
+  ("coloneq", "\x2254"),
+  ("comma", "\x002c"),
+  ("commat", "\x0040"),
+  ("comp", "\x2201"),
+  ("compfn", "\x2218"),
+  ("complement", "\x2201"),
+  ("complexes", "\x2102"),
+  ("cong", "\x2245"),
+  ("congdot", "\x2a6d"),
+  ("conint", "\x222e"),
+  ("copf", "\x1d554"),
+  ("coprod", "\x2210"),
+  ("cop", "\x00a9"),
+  ("copy", "\x00a9"),
+  ("copysr", "\x2117"),
+  ("crarr", "\x21b5"),
+  ("cross", "\x2717"),
+  ("cscr", "\x1d4b8"),
+  ("csub", "\x2acf"),
+  ("csube", "\x2ad1"),
+  ("csup", "\x2ad0"),
+  ("csupe", "\x2ad2"),
+  ("ctdot", "\x22ef"),
+  ("cudarrl", "\x2938"),
+  ("cudarrr", "\x2935"),
+  ("cuepr", "\x22de"),
+  ("cuesc", "\x22df"),
+  ("cularr", "\x21b6"),
+  ("cularrp", "\x293d"),
+  ("cup", "\x222a"),
+  ("cupbrcap", "\x2a48"),
+  ("cupcap", "\x2a46"),
+  ("cupcup", "\x2a4a"),
+  ("cupdot", "\x228d"),
+  ("cupor", "\x2a45"),
+  ("cups", "\x222a\xfe00"),
+  ("curarr", "\x21b7"),
+  ("curarrm", "\x293c"),
+  ("curlyeqprec", "\x22de"),
+  ("curlyeqsucc", "\x22df"),
+  ("curlyvee", "\x22ce"),
+  ("curlywedge", "\x22cf"),
+  ("curre", "\x00a4"),
+  ("curren", "\x00a4"),
+  ("curvearrowleft", "\x21b6"),
+  ("curvearrowright", "\x21b7"),
+  ("cuvee", "\x22ce"),
+  ("cuwed", "\x22cf"),
+  ("cwconint", "\x2232"),
+  ("cwint", "\x2231"),
+  ("cylcty", "\x232d"),
+  ("dArr", "\x21d3"),
+  ("dHar", "\x2965"),
+  ("dagger", "\x2020"),
+  ("daleth", "\x2138"),
+  ("darr", "\x2193"),
+  ("dash", "\x2010"),
+  ("dashv", "\x22a3"),
+  ("dbkarow", "\x290f"),
+  ("dblac", "\x02dd"),
+  ("dcaron", "\x010f"),
+  ("dcy", "\x0434"),
+  ("dd", "\x2146"),
+  ("ddagger", "\x2021"),
+  ("ddarr", "\x21ca"),
+  ("ddotseq", "\x2a77"),
+  ("de", "\x00b0"),
+  ("deg", "\x00b0"),
+  ("delta", "\x03b4"),
+  ("demptyv", "\x29b1"),
+  ("dfisht", "\x297f"),
+  ("dfr", "\x1d521"),
+  ("dharl", "\x21c3"),
+  ("dharr", "\x21c2"),
+  ("diam", "\x22c4"),
+  ("diamond", "\x22c4"),
+  ("diamondsuit", "\x2666"),
+  ("diams", "\x2666"),
+  ("die", "\x00a8"),
+  ("digamma", "\x03dd"),
+  ("disin", "\x22f2"),
+  ("div", "\x00f7"),
+  ("divid", "\x00f7"),
+  ("divide", "\x00f7"),
+  ("divideontimes", "\x22c7"),
+  ("divonx", "\x22c7"),
+  ("djcy", "\x0452"),
+  ("dlcorn", "\x231e"),
+  ("dlcrop", "\x230d"),
+  ("dollar", "\x0024"),
+  ("dopf", "\x1d555"),
+  ("dot", "\x02d9"),
+  ("doteq", "\x2250"),
+  ("doteqdot", "\x2251"),
+  ("dotminus", "\x2238"),
+  ("dotplus", "\x2214"),
+  ("dotsquare", "\x22a1"),
+  ("doublebarwedge", "\x2306"),
+  ("downarrow", "\x2193"),
+  ("downdownarrows", "\x21ca"),
+  ("downharpoonleft", "\x21c3"),
+  ("downharpoonright", "\x21c2"),
+  ("drbkarow", "\x2910"),
+  ("drcorn", "\x231f"),
+  ("drcrop", "\x230c"),
+  ("dscr", "\x1d4b9"),
+  ("dscy", "\x0455"),
+  ("dsol", "\x29f6"),
+  ("dstrok", "\x0111"),
+  ("dtdot", "\x22f1"),
+  ("dtri", "\x25bf"),
+  ("dtrif", "\x25be"),
+  ("duarr", "\x21f5"),
+  ("duhar", "\x296f"),
+  ("dwangle", "\x29a6"),
+  ("dzcy", "\x045f"),
+  ("dzigrarr", "\x27ff"),
+  ("eDDot", "\x2a77"),
+  ("eDot", "\x2251"),
+  ("eacut", "\x00e9"),
+  ("eacute", "\x00e9"),
+  ("easter", "\x2a6e"),
+  ("ecaron", "\x011b"),
+  ("ecir", "\x2256"),
+  ("ecir", "\x00ea"),
+  ("ecirc", "\x00ea"),
+  ("ecolon", "\x2255"),
+  ("ecy", "\x044d"),
+  ("edot", "\x0117"),
+  ("ee", "\x2147"),
+  ("efDot", "\x2252"),
+  ("efr", "\x1d522"),
+  ("eg", "\x2a9a"),
+  ("egrav", "\x00e8"),
+  ("egrave", "\x00e8"),
+  ("egs", "\x2a96"),
+  ("egsdot", "\x2a98"),
+  ("el", "\x2a99"),
+  ("elinters", "\x23e7"),
+  ("ell", "\x2113"),
+  ("els", "\x2a95"),
+  ("elsdot", "\x2a97"),
+  ("emacr", "\x0113"),
+  ("empty", "\x2205"),
+  ("emptyset", "\x2205"),
+  ("emptyv", "\x2205"),
+  ("emsp13", "\x2004"),
+  ("emsp14", "\x2005"),
+  ("emsp", "\x2003"),
+  ("eng", "\x014b"),
+  ("ensp", "\x2002"),
+  ("eogon", "\x0119"),
+  ("eopf", "\x1d556"),
+  ("epar", "\x22d5"),
+  ("eparsl", "\x29e3"),
+  ("eplus", "\x2a71"),
+  ("epsi", "\x03b5"),
+  ("epsilon", "\x03b5"),
+  ("epsiv", "\x03f5"),
+  ("eqcirc", "\x2256"),
+  ("eqcolon", "\x2255"),
+  ("eqsim", "\x2242"),
+  ("eqslantgtr", "\x2a96"),
+  ("eqslantless", "\x2a95"),
+  ("equals", "\x003d"),
+  ("equest", "\x225f"),
+  ("equiv", "\x2261"),
+  ("equivDD", "\x2a78"),
+  ("eqvparsl", "\x29e5"),
+  ("erDot", "\x2253"),
+  ("erarr", "\x2971"),
+  ("escr", "\x212f"),
+  ("esdot", "\x2250"),
+  ("esim", "\x2242"),
+  ("eta", "\x03b7"),
+  ("et", "\x00f0"),
+  ("eth", "\x00f0"),
+  ("eum", "\x00eb"),
+  ("euml", "\x00eb"),
+  ("euro", "\x20ac"),
+  ("excl", "\x0021"),
+  ("exist", "\x2203"),
+  ("expectation", "\x2130"),
+  ("exponentiale", "\x2147"),
+  ("fallingdotseq", "\x2252"),
+  ("fcy", "\x0444"),
+  ("female", "\x2640"),
+  ("ffilig", "\xfb03"),
+  ("fflig", "\xfb00"),
+  ("ffllig", "\xfb04"),
+  ("ffr", "\x1d523"),
+  ("filig", "\xfb01"),
+  ("fjlig", "\x0066\x006a"),
+  ("flat", "\x266d"),
+  ("fllig", "\xfb02"),
+  ("fltns", "\x25b1"),
+  ("fnof", "\x0192"),
+  ("fopf", "\x1d557"),
+  ("forall", "\x2200"),
+  ("fork", "\x22d4"),
+  ("forkv", "\x2ad9"),
+  ("fpartint", "\x2a0d"),
+  ("frac1", "\x00bd"),
+  ("frac12", "\x00bd"),
+  ("frac13", "\x2153"),
+  ("frac1", "\x00bc"),
+  ("frac14", "\x00bc"),
+  ("frac15", "\x2155"),
+  ("frac16", "\x2159"),
+  ("frac18", "\x215b"),
+  ("frac23", "\x2154"),
+  ("frac25", "\x2156"),
+  ("frac3", "\x00be"),
+  ("frac34", "\x00be"),
+  ("frac35", "\x2157"),
+  ("frac38", "\x215c"),
+  ("frac45", "\x2158"),
+  ("frac56", "\x215a"),
+  ("frac58", "\x215d"),
+  ("frac78", "\x215e"),
+  ("frasl", "\x2044"),
+  ("frown", "\x2322"),
+  ("fscr", "\x1d4bb"),
+  ("gE", "\x2267"),
+  ("gEl", "\x2a8c"),
+  ("gacute", "\x01f5"),
+  ("gamma", "\x03b3"),
+  ("gammad", "\x03dd"),
+  ("gap", "\x2a86"),
+  ("gbreve", "\x011f"),
+  ("gcirc", "\x011d"),
+  ("gcy", "\x0433"),
+  ("gdot", "\x0121"),
+  ("ge", "\x2265"),
+  ("gel", "\x22db"),
+  ("geq", "\x2265"),
+  ("geqq", "\x2267"),
+  ("geqslant", "\x2a7e"),
+  ("ges", "\x2a7e"),
+  ("gescc", "\x2aa9"),
+  ("gesdot", "\x2a80"),
+  ("gesdoto", "\x2a82"),
+  ("gesdotol", "\x2a84"),
+  ("gesl", "\x22db\xfe00"),
+  ("gesles", "\x2a94"),
+  ("gfr", "\x1d524"),
+  ("gg", "\x226b"),
+  ("ggg", "\x22d9"),
+  ("gimel", "\x2137"),
+  ("gjcy", "\x0453"),
+  ("gl", "\x2277"),
+  ("glE", "\x2a92"),
+  ("gla", "\x2aa5"),
+  ("glj", "\x2aa4"),
+  ("gnE", "\x2269"),
+  ("gnap", "\x2a8a"),
+  ("gnapprox", "\x2a8a"),
+  ("gne", "\x2a88"),
+  ("gneq", "\x2a88"),
+  ("gneqq", "\x2269"),
+  ("gnsim", "\x22e7"),
+  ("gopf", "\x1d558"),
+  ("grave", "\x0060"),
+  ("gscr", "\x210a"),
+  ("gsim", "\x2273"),
+  ("gsime", "\x2a8e"),
+  ("gsiml", "\x2a90"),
+  ("g", "\x003e"),
+  ("gt", "\x003e"),
+  ("gtcc", "\x2aa7"),
+  ("gtcir", "\x2a7a"),
+  ("gtdot", "\x22d7"),
+  ("gtlPar", "\x2995"),
+  ("gtquest", "\x2a7c"),
+  ("gtrapprox", "\x2a86"),
+  ("gtrarr", "\x2978"),
+  ("gtrdot", "\x22d7"),
+  ("gtreqless", "\x22db"),
+  ("gtreqqless", "\x2a8c"),
+  ("gtrless", "\x2277"),
+  ("gtrsim", "\x2273"),
+  ("gvertneqq", "\x2269\xfe00"),
+  ("gvnE", "\x2269\xfe00"),
+  ("hArr", "\x21d4"),
+  ("hairsp", "\x200a"),
+  ("half", "\x00bd"),
+  ("hamilt", "\x210b"),
+  ("hardcy", "\x044a"),
+  ("harr", "\x2194"),
+  ("harrcir", "\x2948"),
+  ("harrw", "\x21ad"),
+  ("hbar", "\x210f"),
+  ("hcirc", "\x0125"),
+  ("hearts", "\x2665"),
+  ("heartsuit", "\x2665"),
+  ("hellip", "\x2026"),
+  ("hercon", "\x22b9"),
+  ("hfr", "\x1d525"),
+  ("hksearow", "\x2925"),
+  ("hkswarow", "\x2926"),
+  ("hoarr", "\x21ff"),
+  ("homtht", "\x223b"),
+  ("hookleftarrow", "\x21a9"),
+  ("hookrightarrow", "\x21aa"),
+  ("hopf", "\x1d559"),
+  ("horbar", "\x2015"),
+  ("hscr", "\x1d4bd"),
+  ("hslash", "\x210f"),
+  ("hstrok", "\x0127"),
+  ("hybull", "\x2043"),
+  ("hyphen", "\x2010"),
+  ("iacut", "\x00ed"),
+  ("iacute", "\x00ed"),
+  ("ic", "\x2063"),
+  ("icir", "\x00ee"),
+  ("icirc", "\x00ee"),
+  ("icy", "\x0438"),
+  ("iecy", "\x0435"),
+  ("iexc", "\x00a1"),
+  ("iexcl", "\x00a1"),
+  ("iff", "\x21d4"),
+  ("ifr", "\x1d526"),
+  ("igrav", "\x00ec"),
+  ("igrave", "\x00ec"),
+  ("ii", "\x2148"),
+  ("iiiint", "\x2a0c"),
+  ("iiint", "\x222d"),
+  ("iinfin", "\x29dc"),
+  ("iiota", "\x2129"),
+  ("ijlig", "\x0133"),
+  ("imacr", "\x012b"),
+  ("image", "\x2111"),
+  ("imagline", "\x2110"),
+  ("imagpart", "\x2111"),
+  ("imath", "\x0131"),
+  ("imof", "\x22b7"),
+  ("imped", "\x01b5"),
+  ("in", "\x2208"),
+  ("incare", "\x2105"),
+  ("infin", "\x221e"),
+  ("infintie", "\x29dd"),
+  ("inodot", "\x0131"),
+  ("int", "\x222b"),
+  ("intcal", "\x22ba"),
+  ("integers", "\x2124"),
+  ("intercal", "\x22ba"),
+  ("intlarhk", "\x2a17"),
+  ("intprod", "\x2a3c"),
+  ("iocy", "\x0451"),
+  ("iogon", "\x012f"),
+  ("iopf", "\x1d55a"),
+  ("iota", "\x03b9"),
+  ("iprod", "\x2a3c"),
+  ("iques", "\x00bf"),
+  ("iquest", "\x00bf"),
+  ("iscr", "\x1d4be"),
+  ("isin", "\x2208"),
+  ("isinE", "\x22f9"),
+  ("isindot", "\x22f5"),
+  ("isins", "\x22f4"),
+  ("isinsv", "\x22f3"),
+  ("isinv", "\x2208"),
+  ("it", "\x2062"),
+  ("itilde", "\x0129"),
+  ("iukcy", "\x0456"),
+  ("ium", "\x00ef"),
+  ("iuml", "\x00ef"),
+  ("jcirc", "\x0135"),
+  ("jcy", "\x0439"),
+  ("jfr", "\x1d527"),
+  ("jmath", "\x0237"),
+  ("jopf", "\x1d55b"),
+  ("jscr", "\x1d4bf"),
+  ("jsercy", "\x0458"),
+  ("jukcy", "\x0454"),
+  ("kappa", "\x03ba"),
+  ("kappav", "\x03f0"),
+  ("kcedil", "\x0137"),
+  ("kcy", "\x043a"),
+  ("kfr", "\x1d528"),
+  ("kgreen", "\x0138"),
+  ("khcy", "\x0445"),
+  ("kjcy", "\x045c"),
+  ("kopf", "\x1d55c"),
+  ("kscr", "\x1d4c0"),
+  ("lAarr", "\x21da"),
+  ("lArr", "\x21d0"),
+  ("lAtail", "\x291b"),
+  ("lBarr", "\x290e"),
+  ("lE", "\x2266"),
+  ("lEg", "\x2a8b"),
+  ("lHar", "\x2962"),
+  ("lacute", "\x013a"),
+  ("laemptyv", "\x29b4"),
+  ("lagran", "\x2112"),
+  ("lambda", "\x03bb"),
+  ("lang", "\x27e8"),
+  ("langd", "\x2991"),
+  ("langle", "\x27e8"),
+  ("lap", "\x2a85"),
+  ("laqu", "\x00ab"),
+  ("laquo", "\x00ab"),
+  ("larr", "\x2190"),
+  ("larrb", "\x21e4"),
+  ("larrbfs", "\x291f"),
+  ("larrfs", "\x291d"),
+  ("larrhk", "\x21a9"),
+  ("larrlp", "\x21ab"),
+  ("larrpl", "\x2939"),
+  ("larrsim", "\x2973"),
+  ("larrtl", "\x21a2"),
+  ("lat", "\x2aab"),
+  ("latail", "\x2919"),
+  ("late", "\x2aad"),
+  ("lates", "\x2aad\xfe00"),
+  ("lbarr", "\x290c"),
+  ("lbbrk", "\x2772"),
+  ("lbrace", "\x007b"),
+  ("lbrack", "\x005b"),
+  ("lbrke", "\x298b"),
+  ("lbrksld", "\x298f"),
+  ("lbrkslu", "\x298d"),
+  ("lcaron", "\x013e"),
+  ("lcedil", "\x013c"),
+  ("lceil", "\x2308"),
+  ("lcub", "\x007b"),
+  ("lcy", "\x043b"),
+  ("ldca", "\x2936"),
+  ("ldquo", "\x201c"),
+  ("ldquor", "\x201e"),
+  ("ldrdhar", "\x2967"),
+  ("ldrushar", "\x294b"),
+  ("ldsh", "\x21b2"),
+  ("le", "\x2264"),
+  ("leftarrow", "\x2190"),
+  ("leftarrowtail", "\x21a2"),
+  ("leftharpoondown", "\x21bd"),
+  ("leftharpoonup", "\x21bc"),
+  ("leftleftarrows", "\x21c7"),
+  ("leftrightarrow", "\x2194"),
+  ("leftrightarrows", "\x21c6"),
+  ("leftrightharpoons", "\x21cb"),
+  ("leftrightsquigarrow", "\x21ad"),
+  ("leftthreetimes", "\x22cb"),
+  ("leg", "\x22da"),
+  ("leq", "\x2264"),
+  ("leqq", "\x2266"),
+  ("leqslant", "\x2a7d"),
+  ("les", "\x2a7d"),
+  ("lescc", "\x2aa8"),
+  ("lesdot", "\x2a7f"),
+  ("lesdoto", "\x2a81"),
+  ("lesdotor", "\x2a83"),
+  ("lesg", "\x22da\xfe00"),
+  ("lesges", "\x2a93"),
+  ("lessapprox", "\x2a85"),
+  ("lessdot", "\x22d6"),
+  ("lesseqgtr", "\x22da"),
+  ("lesseqqgtr", "\x2a8b"),
+  ("lessgtr", "\x2276"),
+  ("lesssim", "\x2272"),
+  ("lfisht", "\x297c"),
+  ("lfloor", "\x230a"),
+  ("lfr", "\x1d529"),
+  ("lg", "\x2276"),
+  ("lgE", "\x2a91"),
+  ("lhard", "\x21bd"),
+  ("lharu", "\x21bc"),
+  ("lharul", "\x296a"),
+  ("lhblk", "\x2584"),
+  ("ljcy", "\x0459"),
+  ("ll", "\x226a"),
+  ("llarr", "\x21c7"),
+  ("llcorner", "\x231e"),
+  ("llhard", "\x296b"),
+  ("lltri", "\x25fa"),
+  ("lmidot", "\x0140"),
+  ("lmoust", "\x23b0"),
+  ("lmoustache", "\x23b0"),
+  ("lnE", "\x2268"),
+  ("lnap", "\x2a89"),
+  ("lnapprox", "\x2a89"),
+  ("lne", "\x2a87"),
+  ("lneq", "\x2a87"),
+  ("lneqq", "\x2268"),
+  ("lnsim", "\x22e6"),
+  ("loang", "\x27ec"),
+  ("loarr", "\x21fd"),
+  ("lobrk", "\x27e6"),
+  ("longleftarrow", "\x27f5"),
+  ("longleftrightarrow", "\x27f7"),
+  ("longmapsto", "\x27fc"),
+  ("longrightarrow", "\x27f6"),
+  ("looparrowleft", "\x21ab"),
+  ("looparrowright", "\x21ac"),
+  ("lopar", "\x2985"),
+  ("lopf", "\x1d55d"),
+  ("loplus", "\x2a2d"),
+  ("lotimes", "\x2a34"),
+  ("lowast", "\x2217"),
+  ("lowbar", "\x005f"),
+  ("loz", "\x25ca"),
+  ("lozenge", "\x25ca"),
+  ("lozf", "\x29eb"),
+  ("lpar", "\x0028"),
+  ("lparlt", "\x2993"),
+  ("lrarr", "\x21c6"),
+  ("lrcorner", "\x231f"),
+  ("lrhar", "\x21cb"),
+  ("lrhard", "\x296d"),
+  ("lrm", "\x200e"),
+  ("lrtri", "\x22bf"),
+  ("lsaquo", "\x2039"),
+  ("lscr", "\x1d4c1"),
+  ("lsh", "\x21b0"),
+  ("lsim", "\x2272"),
+  ("lsime", "\x2a8d"),
+  ("lsimg", "\x2a8f"),
+  ("lsqb", "\x005b"),
+  ("lsquo", "\x2018"),
+  ("lsquor", "\x201a"),
+  ("lstrok", "\x0142"),
+  ("l", "\x003c"),
+  ("lt", "\x003c"),
+  ("ltcc", "\x2aa6"),
+  ("ltcir", "\x2a79"),
+  ("ltdot", "\x22d6"),
+  ("lthree", "\x22cb"),
+  ("ltimes", "\x22c9"),
+  ("ltlarr", "\x2976"),
+  ("ltquest", "\x2a7b"),
+  ("ltrPar", "\x2996"),
+  ("ltri", "\x25c3"),
+  ("ltrie", "\x22b4"),
+  ("ltrif", "\x25c2"),
+  ("lurdshar", "\x294a"),
+  ("luruhar", "\x2966"),
+  ("lvertneqq", "\x2268\xfe00"),
+  ("lvnE", "\x2268\xfe00"),
+  ("mDDot", "\x223a"),
+  ("mac", "\x00af"),
+  ("macr", "\x00af"),
+  ("male", "\x2642"),
+  ("malt", "\x2720"),
+  ("maltese", "\x2720"),
+  ("map", "\x21a6"),
+  ("mapsto", "\x21a6"),
+  ("mapstodown", "\x21a7"),
+  ("mapstoleft", "\x21a4"),
+  ("mapstoup", "\x21a5"),
+  ("marker", "\x25ae"),
+  ("mcomma", "\x2a29"),
+  ("mcy", "\x043c"),
+  ("mdash", "\x2014"),
+  ("measuredangle", "\x2221"),
+  ("mfr", "\x1d52a"),
+  ("mho", "\x2127"),
+  ("micr", "\x00b5"),
+  ("micro", "\x00b5"),
+  ("mid", "\x2223"),
+  ("midast", "\x002a"),
+  ("midcir", "\x2af0"),
+  ("middo", "\x00b7"),
+  ("middot", "\x00b7"),
+  ("minus", "\x2212"),
+  ("minusb", "\x229f"),
+  ("minusd", "\x2238"),
+  ("minusdu", "\x2a2a"),
+  ("mlcp", "\x2adb"),
+  ("mldr", "\x2026"),
+  ("mnplus", "\x2213"),
+  ("models", "\x22a7"),
+  ("mopf", "\x1d55e"),
+  ("mp", "\x2213"),
+  ("mscr", "\x1d4c2"),
+  ("mstpos", "\x223e"),
+  ("mu", "\x03bc"),
+  ("multimap", "\x22b8"),
+  ("mumap", "\x22b8"),
+  ("nGg", "\x22d9\x0338"),
+  ("nGt", "\x226b\x20d2"),
+  ("nGtv", "\x226b\x0338"),
+  ("nLeftarrow", "\x21cd"),
+  ("nLeftrightarrow", "\x21ce"),
+  ("nLl", "\x22d8\x0338"),
+  ("nLt", "\x226a\x20d2"),
+  ("nLtv", "\x226a\x0338"),
+  ("nRightarrow", "\x21cf"),
+  ("nVDash", "\x22af"),
+  ("nVdash", "\x22ae"),
+  ("nabla", "\x2207"),
+  ("nacute", "\x0144"),
+  ("nang", "\x2220\x20d2"),
+  ("nap", "\x2249"),
+  ("napE", "\x2a70\x0338"),
+  ("napid", "\x224b\x0338"),
+  ("napos", "\x0149"),
+  ("napprox", "\x2249"),
+  ("natur", "\x266e"),
+  ("natural", "\x266e"),
+  ("naturals", "\x2115"),
+  ("nbs", "\x00a0"),
+  ("nbsp", "\x00a0"),
+  ("nbump", "\x224e\x0338"),
+  ("nbumpe", "\x224f\x0338"),
+  ("ncap", "\x2a43"),
+  ("ncaron", "\x0148"),
+  ("ncedil", "\x0146"),
+  ("ncong", "\x2247"),
+  ("ncongdot", "\x2a6d\x0338"),
+  ("ncup", "\x2a42"),
+  ("ncy", "\x043d"),
+  ("ndash", "\x2013"),
+  ("ne", "\x2260"),
+  ("neArr", "\x21d7"),
+  ("nearhk", "\x2924"),
+  ("nearr", "\x2197"),
+  ("nearrow", "\x2197"),
+  ("nedot", "\x2250\x0338"),
+  ("nequiv", "\x2262"),
+  ("nesear", "\x2928"),
+  ("nesim", "\x2242\x0338"),
+  ("nexist", "\x2204"),
+  ("nexists", "\x2204"),
+  ("nfr", "\x1d52b"),
+  ("ngE", "\x2267\x0338"),
+  ("nge", "\x2271"),
+  ("ngeq", "\x2271"),
+  ("ngeqq", "\x2267\x0338"),
+  ("ngeqslant", "\x2a7e\x0338"),
+  ("nges", "\x2a7e\x0338"),
+  ("ngsim", "\x2275"),
+  ("ngt", "\x226f"),
+  ("ngtr", "\x226f"),
+  ("nhArr", "\x21ce"),
+  ("nharr", "\x21ae"),
+  ("nhpar", "\x2af2"),
+  ("ni", "\x220b"),
+  ("nis", "\x22fc"),
+  ("nisd", "\x22fa"),
+  ("niv", "\x220b"),
+  ("njcy", "\x045a"),
+  ("nlArr", "\x21cd"),
+  ("nlE", "\x2266\x0338"),
+  ("nlarr", "\x219a"),
+  ("nldr", "\x2025"),
+  ("nle", "\x2270"),
+  ("nleftarrow", "\x219a"),
+  ("nleftrightarrow", "\x21ae"),
+  ("nleq", "\x2270"),
+  ("nleqq", "\x2266\x0338"),
+  ("nleqslant", "\x2a7d\x0338"),
+  ("nles", "\x2a7d\x0338"),
+  ("nless", "\x226e"),
+  ("nlsim", "\x2274"),
+  ("nlt", "\x226e"),
+  ("nltri", "\x22ea"),
+  ("nltrie", "\x22ec"),
+  ("nmid", "\x2224"),
+  ("nopf", "\x1d55f"),
+  ("no", "\x00ac"),
+  ("not", "\x00ac"),
+  ("notin", "\x2209"),
+  ("notinE", "\x22f9\x0338"),
+  ("notindot", "\x22f5\x0338"),
+  ("notinva", "\x2209"),
+  ("notinvb", "\x22f7"),
+  ("notinvc", "\x22f6"),
+  ("notni", "\x220c"),
+  ("notniva", "\x220c"),
+  ("notnivb", "\x22fe"),
+  ("notnivc", "\x22fd"),
+  ("npar", "\x2226"),
+  ("nparallel", "\x2226"),
+  ("nparsl", "\x2afd\x20e5"),
+  ("npart", "\x2202\x0338"),
+  ("npolint", "\x2a14"),
+  ("npr", "\x2280"),
+  ("nprcue", "\x22e0"),
+  ("npre", "\x2aaf\x0338"),
+  ("nprec", "\x2280"),
+  ("npreceq", "\x2aaf\x0338"),
+  ("nrArr", "\x21cf"),
+  ("nrarr", "\x219b"),
+  ("nrarrc", "\x2933\x0338"),
+  ("nrarrw", "\x219d\x0338"),
+  ("nrightarrow", "\x219b"),
+  ("nrtri", "\x22eb"),
+  ("nrtrie", "\x22ed"),
+  ("nsc", "\x2281"),
+  ("nsccue", "\x22e1"),
+  ("nsce", "\x2ab0\x0338"),
+  ("nscr", "\x1d4c3"),
+  ("nshortmid", "\x2224"),
+  ("nshortparallel", "\x2226"),
+  ("nsim", "\x2241"),
+  ("nsime", "\x2244"),
+  ("nsimeq", "\x2244"),
+  ("nsmid", "\x2224"),
+  ("nspar", "\x2226"),
+  ("nsqsube", "\x22e2"),
+  ("nsqsupe", "\x22e3"),
+  ("nsub", "\x2284"),
+  ("nsubE", "\x2ac5\x0338"),
+  ("nsube", "\x2288"),
+  ("nsubset", "\x2282\x20d2"),
+  ("nsubseteq", "\x2288"),
+  ("nsubseteqq", "\x2ac5\x0338"),
+  ("nsucc", "\x2281"),
+  ("nsucceq", "\x2ab0\x0338"),
+  ("nsup", "\x2285"),
+  ("nsupE", "\x2ac6\x0338"),
+  ("nsupe", "\x2289"),
+  ("nsupset", "\x2283\x20d2"),
+  ("nsupseteq", "\x2289"),
+  ("nsupseteqq", "\x2ac6\x0338"),
+  ("ntgl", "\x2279"),
+  ("ntild", "\x00f1"),
+  ("ntilde", "\x00f1"),
+  ("ntlg", "\x2278"),
+  ("ntriangleleft", "\x22ea"),
+  ("ntrianglelefteq", "\x22ec"),
+  ("ntriangleright", "\x22eb"),
+  ("ntrianglerighteq", "\x22ed"),
+  ("nu", "\x03bd"),
+  ("num", "\x0023"),
+  ("numero", "\x2116"),
+  ("numsp", "\x2007"),
+  ("nvDash", "\x22ad"),
+  ("nvHarr", "\x2904"),
+  ("nvap", "\x224d\x20d2"),
+  ("nvdash", "\x22ac"),
+  ("nvge", "\x2265\x20d2"),
+  ("nvgt", "\x003e\x20d2"),
+  ("nvinfin", "\x29de"),
+  ("nvlArr", "\x2902"),
+  ("nvle", "\x2264\x20d2"),
+  ("nvlt", "\x003c\x20d2"),
+  ("nvltrie", "\x22b4\x20d2"),
+  ("nvrArr", "\x2903"),
+  ("nvrtrie", "\x22b5\x20d2"),
+  ("nvsim", "\x223c\x20d2"),
+  ("nwArr", "\x21d6"),
+  ("nwarhk", "\x2923"),
+  ("nwarr", "\x2196"),
+  ("nwarrow", "\x2196"),
+  ("nwnear", "\x2927"),
+  ("oS", "\x24c8"),
+  ("oacut", "\x00f3"),
+  ("oacute", "\x00f3"),
+  ("oast", "\x229b"),
+  ("ocir", "\x229a"),
+  ("ocir", "\x00f4"),
+  ("ocirc", "\x00f4"),
+  ("ocy", "\x043e"),
+  ("odash", "\x229d"),
+  ("odblac", "\x0151"),
+  ("odiv", "\x2a38"),
+  ("odot", "\x2299"),
+  ("odsold", "\x29bc"),
+  ("oelig", "\x0153"),
+  ("ofcir", "\x29bf"),
+  ("ofr", "\x1d52c"),
+  ("ogon", "\x02db"),
+  ("ograv", "\x00f2"),
+  ("ograve", "\x00f2"),
+  ("ogt", "\x29c1"),
+  ("ohbar", "\x29b5"),
+  ("ohm", "\x03a9"),
+  ("oint", "\x222e"),
+  ("olarr", "\x21ba"),
+  ("olcir", "\x29be"),
+  ("olcross", "\x29bb"),
+  ("oline", "\x203e"),
+  ("olt", "\x29c0"),
+  ("omacr", "\x014d"),
+  ("omega", "\x03c9"),
+  ("omicron", "\x03bf"),
+  ("omid", "\x29b6"),
+  ("ominus", "\x2296"),
+  ("oopf", "\x1d560"),
+  ("opar", "\x29b7"),
+  ("operp", "\x29b9"),
+  ("oplus", "\x2295"),
+  ("or", "\x2228"),
+  ("orarr", "\x21bb"),
+  ("ord", "\x2a5d"),
+  ("order", "\x2134"),
+  ("orderof", "\x2134"),
+  ("ord", "\x00aa"),
+  ("ordf", "\x00aa"),
+  ("ord", "\x00ba"),
+  ("ordm", "\x00ba"),
+  ("origof", "\x22b6"),
+  ("oror", "\x2a56"),
+  ("orslope", "\x2a57"),
+  ("orv", "\x2a5b"),
+  ("oscr", "\x2134"),
+  ("oslas", "\x00f8"),
+  ("oslash", "\x00f8"),
+  ("osol", "\x2298"),
+  ("otild", "\x00f5"),
+  ("otilde", "\x00f5"),
+  ("otimes", "\x2297"),
+  ("otimesas", "\x2a36"),
+  ("oum", "\x00f6"),
+  ("ouml", "\x00f6"),
+  ("ovbar", "\x233d"),
+  ("par", "\x2225"),
+  ("par", "\x00b6"),
+  ("para", "\x00b6"),
+  ("parallel", "\x2225"),
+  ("parsim", "\x2af3"),
+  ("parsl", "\x2afd"),
+  ("part", "\x2202"),
+  ("pcy", "\x043f"),
+  ("percnt", "\x0025"),
+  ("period", "\x002e"),
+  ("permil", "\x2030"),
+  ("perp", "\x22a5"),
+  ("pertenk", "\x2031"),
+  ("pfr", "\x1d52d"),
+  ("phi", "\x03c6"),
+  ("phiv", "\x03d5"),
+  ("phmmat", "\x2133"),
+  ("phone", "\x260e"),
+  ("pi", "\x03c0"),
+  ("pitchfork", "\x22d4"),
+  ("piv", "\x03d6"),
+  ("planck", "\x210f"),
+  ("planckh", "\x210e"),
+  ("plankv", "\x210f"),
+  ("plus", "\x002b"),
+  ("plusacir", "\x2a23"),
+  ("plusb", "\x229e"),
+  ("pluscir", "\x2a22"),
+  ("plusdo", "\x2214"),
+  ("plusdu", "\x2a25"),
+  ("pluse", "\x2a72"),
+  ("plusm", "\x00b1"),
+  ("plusmn", "\x00b1"),
+  ("plussim", "\x2a26"),
+  ("plustwo", "\x2a27"),
+  ("pm", "\x00b1"),
+  ("pointint", "\x2a15"),
+  ("popf", "\x1d561"),
+  ("poun", "\x00a3"),
+  ("pound", "\x00a3"),
+  ("pr", "\x227a"),
+  ("prE", "\x2ab3"),
+  ("prap", "\x2ab7"),
+  ("prcue", "\x227c"),
+  ("pre", "\x2aaf"),
+  ("prec", "\x227a"),
+  ("precapprox", "\x2ab7"),
+  ("preccurlyeq", "\x227c"),
+  ("preceq", "\x2aaf"),
+  ("precnapprox", "\x2ab9"),
+  ("precneqq", "\x2ab5"),
+  ("precnsim", "\x22e8"),
+  ("precsim", "\x227e"),
+  ("prime", "\x2032"),
+  ("primes", "\x2119"),
+  ("prnE", "\x2ab5"),
+  ("prnap", "\x2ab9"),
+  ("prnsim", "\x22e8"),
+  ("prod", "\x220f"),
+  ("profalar", "\x232e"),
+  ("profline", "\x2312"),
+  ("profsurf", "\x2313"),
+  ("prop", "\x221d"),
+  ("propto", "\x221d"),
+  ("prsim", "\x227e"),
+  ("prurel", "\x22b0"),
+  ("pscr", "\x1d4c5"),
+  ("psi", "\x03c8"),
+  ("puncsp", "\x2008"),
+  ("qfr", "\x1d52e"),
+  ("qint", "\x2a0c"),
+  ("qopf", "\x1d562"),
+  ("qprime", "\x2057"),
+  ("qscr", "\x1d4c6"),
+  ("quaternions", "\x210d"),
+  ("quatint", "\x2a16"),
+  ("quest", "\x003f"),
+  ("questeq", "\x225f"),
+  ("quo", "\x0022"),
+  ("quot", "\x0022"),
+  ("rAarr", "\x21db"),
+  ("rArr", "\x21d2"),
+  ("rAtail", "\x291c"),
+  ("rBarr", "\x290f"),
+  ("rHar", "\x2964"),
+  ("race", "\x223d\x0331"),
+  ("racute", "\x0155"),
+  ("radic", "\x221a"),
+  ("raemptyv", "\x29b3"),
+  ("rang", "\x27e9"),
+  ("rangd", "\x2992"),
+  ("range", "\x29a5"),
+  ("rangle", "\x27e9"),
+  ("raqu", "\x00bb"),
+  ("raquo", "\x00bb"),
+  ("rarr", "\x2192"),
+  ("rarrap", "\x2975"),
+  ("rarrb", "\x21e5"),
+  ("rarrbfs", "\x2920"),
+  ("rarrc", "\x2933"),
+  ("rarrfs", "\x291e"),
+  ("rarrhk", "\x21aa"),
+  ("rarrlp", "\x21ac"),
+  ("rarrpl", "\x2945"),
+  ("rarrsim", "\x2974"),
+  ("rarrtl", "\x21a3"),
+  ("rarrw", "\x219d"),
+  ("ratail", "\x291a"),
+  ("ratio", "\x2236"),
+  ("rationals", "\x211a"),
+  ("rbarr", "\x290d"),
+  ("rbbrk", "\x2773"),
+  ("rbrace", "\x007d"),
+  ("rbrack", "\x005d"),
+  ("rbrke", "\x298c"),
+  ("rbrksld", "\x298e"),
+  ("rbrkslu", "\x2990"),
+  ("rcaron", "\x0159"),
+  ("rcedil", "\x0157"),
+  ("rceil", "\x2309"),
+  ("rcub", "\x007d"),
+  ("rcy", "\x0440"),
+  ("rdca", "\x2937"),
+  ("rdldhar", "\x2969"),
+  ("rdquo", "\x201d"),
+  ("rdquor", "\x201d"),
+  ("rdsh", "\x21b3"),
+  ("real", "\x211c"),
+  ("realine", "\x211b"),
+  ("realpart", "\x211c"),
+  ("reals", "\x211d"),
+  ("rect", "\x25ad"),
+  ("re", "\x00ae"),
+  ("reg", "\x00ae"),
+  ("rfisht", "\x297d"),
+  ("rfloor", "\x230b"),
+  ("rfr", "\x1d52f"),
+  ("rhard", "\x21c1"),
+  ("rharu", "\x21c0"),
+  ("rharul", "\x296c"),
+  ("rho", "\x03c1"),
+  ("rhov", "\x03f1"),
+  ("rightarrow", "\x2192"),
+  ("rightarrowtail", "\x21a3"),
+  ("rightharpoondown", "\x21c1"),
+  ("rightharpoonup", "\x21c0"),
+  ("rightleftarrows", "\x21c4"),
+  ("rightleftharpoons", "\x21cc"),
+  ("rightrightarrows", "\x21c9"),
+  ("rightsquigarrow", "\x219d"),
+  ("rightthreetimes", "\x22cc"),
+  ("ring", "\x02da"),
+  ("risingdotseq", "\x2253"),
+  ("rlarr", "\x21c4"),
+  ("rlhar", "\x21cc"),
+  ("rlm", "\x200f"),
+  ("rmoust", "\x23b1"),
+  ("rmoustache", "\x23b1"),
+  ("rnmid", "\x2aee"),
+  ("roang", "\x27ed"),
+  ("roarr", "\x21fe"),
+  ("robrk", "\x27e7"),
+  ("ropar", "\x2986"),
+  ("ropf", "\x1d563"),
+  ("roplus", "\x2a2e"),
+  ("rotimes", "\x2a35"),
+  ("rpar", "\x0029"),
+  ("rpargt", "\x2994"),
+  ("rppolint", "\x2a12"),
+  ("rrarr", "\x21c9"),
+  ("rsaquo", "\x203a"),
+  ("rscr", "\x1d4c7"),
+  ("rsh", "\x21b1"),
+  ("rsqb", "\x005d"),
+  ("rsquo", "\x2019"),
+  ("rsquor", "\x2019"),
+  ("rthree", "\x22cc"),
+  ("rtimes", "\x22ca"),
+  ("rtri", "\x25b9"),
+  ("rtrie", "\x22b5"),
+  ("rtrif", "\x25b8"),
+  ("rtriltri", "\x29ce"),
+  ("ruluhar", "\x2968"),
+  ("rx", "\x211e"),
+  ("sacute", "\x015b"),
+  ("sbquo", "\x201a"),
+  ("sc", "\x227b"),
+  ("scE", "\x2ab4"),
+  ("scap", "\x2ab8"),
+  ("scaron", "\x0161"),
+  ("sccue", "\x227d"),
+  ("sce", "\x2ab0"),
+  ("scedil", "\x015f"),
+  ("scirc", "\x015d"),
+  ("scnE", "\x2ab6"),
+  ("scnap", "\x2aba"),
+  ("scnsim", "\x22e9"),
+  ("scpolint", "\x2a13"),
+  ("scsim", "\x227f"),
+  ("scy", "\x0441"),
+  ("sdot", "\x22c5"),
+  ("sdotb", "\x22a1"),
+  ("sdote", "\x2a66"),
+  ("seArr", "\x21d8"),
+  ("searhk", "\x2925"),
+  ("searr", "\x2198"),
+  ("searrow", "\x2198"),
+  ("sec", "\x00a7"),
+  ("sect", "\x00a7"),
+  ("semi", "\x003b"),
+  ("seswar", "\x2929"),
+  ("setminus", "\x2216"),
+  ("setmn", "\x2216"),
+  ("sext", "\x2736"),
+  ("sfr", "\x1d530"),
+  ("sfrown", "\x2322"),
+  ("sharp", "\x266f"),
+  ("shchcy", "\x0449"),
+  ("shcy", "\x0448"),
+  ("shortmid", "\x2223"),
+  ("shortparallel", "\x2225"),
+  ("sh", "\x00ad"),
+  ("shy", "\x00ad"),
+  ("sigma", "\x03c3"),
+  ("sigmaf", "\x03c2"),
+  ("sigmav", "\x03c2"),
+  ("sim", "\x223c"),
+  ("simdot", "\x2a6a"),
+  ("sime", "\x2243"),
+  ("simeq", "\x2243"),
+  ("simg", "\x2a9e"),
+  ("simgE", "\x2aa0"),
+  ("siml", "\x2a9d"),
+  ("simlE", "\x2a9f"),
+  ("simne", "\x2246"),
+  ("simplus", "\x2a24"),
+  ("simrarr", "\x2972"),
+  ("slarr", "\x2190"),
+  ("smallsetminus", "\x2216"),
+  ("smashp", "\x2a33"),
+  ("smeparsl", "\x29e4"),
+  ("smid", "\x2223"),
+  ("smile", "\x2323"),
+  ("smt", "\x2aaa"),
+  ("smte", "\x2aac"),
+  ("smtes", "\x2aac\xfe00"),
+  ("softcy", "\x044c"),
+  ("sol", "\x002f"),
+  ("solb", "\x29c4"),
+  ("solbar", "\x233f"),
+  ("sopf", "\x1d564"),
+  ("spades", "\x2660"),
+  ("spadesuit", "\x2660"),
+  ("spar", "\x2225"),
+  ("sqcap", "\x2293"),
+  ("sqcaps", "\x2293\xfe00"),
+  ("sqcup", "\x2294"),
+  ("sqcups", "\x2294\xfe00"),
+  ("sqsub", "\x228f"),
+  ("sqsube", "\x2291"),
+  ("sqsubset", "\x228f"),
+  ("sqsubseteq", "\x2291"),
+  ("sqsup", "\x2290"),
+  ("sqsupe", "\x2292"),
+  ("sqsupset", "\x2290"),
+  ("sqsupseteq", "\x2292"),
+  ("squ", "\x25a1"),
+  ("square", "\x25a1"),
+  ("squarf", "\x25aa"),
+  ("squf", "\x25aa"),
+  ("srarr", "\x2192"),
+  ("sscr", "\x1d4c8"),
+  ("ssetmn", "\x2216"),
+  ("ssmile", "\x2323"),
+  ("sstarf", "\x22c6"),
+  ("star", "\x2606"),
+  ("starf", "\x2605"),
+  ("straightepsilon", "\x03f5"),
+  ("straightphi", "\x03d5"),
+  ("strns", "\x00af"),
+  ("sub", "\x2282"),
+  ("subE", "\x2ac5"),
+  ("subdot", "\x2abd"),
+  ("sube", "\x2286"),
+  ("subedot", "\x2ac3"),
+  ("submult", "\x2ac1"),
+  ("subnE", "\x2acb"),
+  ("subne", "\x228a"),
+  ("subplus", "\x2abf"),
+  ("subrarr", "\x2979"),
+  ("subset", "\x2282"),
+  ("subseteq", "\x2286"),
+  ("subseteqq", "\x2ac5"),
+  ("subsetneq", "\x228a"),
+  ("subsetneqq", "\x2acb"),
+  ("subsim", "\x2ac7"),
+  ("subsub", "\x2ad5"),
+  ("subsup", "\x2ad3"),
+  ("succ", "\x227b"),
+  ("succapprox", "\x2ab8"),
+  ("succcurlyeq", "\x227d"),
+  ("succeq", "\x2ab0"),
+  ("succnapprox", "\x2aba"),
+  ("succneqq", "\x2ab6"),
+  ("succnsim", "\x22e9"),
+  ("succsim", "\x227f"),
+  ("sum", "\x2211"),
+  ("sung", "\x266a"),
+  ("sup", "\x00b9"),
+  ("sup1", "\x00b9"),
+  ("sup", "\x00b2"),
+  ("sup2", "\x00b2"),
+  ("sup", "\x00b3"),
+  ("sup3", "\x00b3"),
+  ("sup", "\x2283"),
+  ("supE", "\x2ac6"),
+  ("supdot", "\x2abe"),
+  ("supdsub", "\x2ad8"),
+  ("supe", "\x2287"),
+  ("supedot", "\x2ac4"),
+  ("suphsol", "\x27c9"),
+  ("suphsub", "\x2ad7"),
+  ("suplarr", "\x297b"),
+  ("supmult", "\x2ac2"),
+  ("supnE", "\x2acc"),
+  ("supne", "\x228b"),
+  ("supplus", "\x2ac0"),
+  ("supset", "\x2283"),
+  ("supseteq", "\x2287"),
+  ("supseteqq", "\x2ac6"),
+  ("supsetneq", "\x228b"),
+  ("supsetneqq", "\x2acc"),
+  ("supsim", "\x2ac8"),
+  ("supsub", "\x2ad4"),
+  ("supsup", "\x2ad6"),
+  ("swArr", "\x21d9"),
+  ("swarhk", "\x2926"),
+  ("swarr", "\x2199"),
+  ("swarrow", "\x2199"),
+  ("swnwar", "\x292a"),
+  ("szli", "\x00df"),
+  ("szlig", "\x00df"),
+  ("target", "\x2316"),
+  ("tau", "\x03c4"),
+  ("tbrk", "\x23b4"),
+  ("tcaron", "\x0165"),
+  ("tcedil", "\x0163"),
+  ("tcy", "\x0442"),
+  ("tdot", "\x20db"),
+  ("telrec", "\x2315"),
+  ("tfr", "\x1d531"),
+  ("there4", "\x2234"),
+  ("therefore", "\x2234"),
+  ("theta", "\x03b8"),
+  ("thetasym", "\x03d1"),
+  ("thetav", "\x03d1"),
+  ("thickapprox", "\x2248"),
+  ("thicksim", "\x223c"),
+  ("thinsp", "\x2009"),
+  ("thkap", "\x2248"),
+  ("thksim", "\x223c"),
+  ("thor", "\x00fe"),
+  ("thorn", "\x00fe"),
+  ("tilde", "\x02dc"),
+  ("time", "\x00d7"),
+  ("times", "\x00d7"),
+  ("timesb", "\x22a0"),
+  ("timesbar", "\x2a31"),
+  ("timesd", "\x2a30"),
+  ("tint", "\x222d"),
+  ("toea", "\x2928"),
+  ("top", "\x22a4"),
+  ("topbot", "\x2336"),
+  ("topcir", "\x2af1"),
+  ("topf", "\x1d565"),
+  ("topfork", "\x2ada"),
+  ("tosa", "\x2929"),
+  ("tprime", "\x2034"),
+  ("trade", "\x2122"),
+  ("triangle", "\x25b5"),
+  ("triangledown", "\x25bf"),
+  ("triangleleft", "\x25c3"),
+  ("trianglelefteq", "\x22b4"),
+  ("triangleq", "\x225c"),
+  ("triangleright", "\x25b9"),
+  ("trianglerighteq", "\x22b5"),
+  ("tridot", "\x25ec"),
+  ("trie", "\x225c"),
+  ("triminus", "\x2a3a"),
+  ("triplus", "\x2a39"),
+  ("trisb", "\x29cd"),
+  ("tritime", "\x2a3b"),
+  ("trpezium", "\x23e2"),
+  ("tscr", "\x1d4c9"),
+  ("tscy", "\x0446"),
+  ("tshcy", "\x045b"),
+  ("tstrok", "\x0167"),
+  ("twixt", "\x226c"),
+  ("twoheadleftarrow", "\x219e"),
+  ("twoheadrightarrow", "\x21a0"),
+  ("uArr", "\x21d1"),
+  ("uHar", "\x2963"),
+  ("uacut", "\x00fa"),
+  ("uacute", "\x00fa"),
+  ("uarr", "\x2191"),
+  ("ubrcy", "\x045e"),
+  ("ubreve", "\x016d"),
+  ("ucir", "\x00fb"),
+  ("ucirc", "\x00fb"),
+  ("ucy", "\x0443"),
+  ("udarr", "\x21c5"),
+  ("udblac", "\x0171"),
+  ("udhar", "\x296e"),
+  ("ufisht", "\x297e"),
+  ("ufr", "\x1d532"),
+  ("ugrav", "\x00f9"),
+  ("ugrave", "\x00f9"),
+  ("uharl", "\x21bf"),
+  ("uharr", "\x21be"),
+  ("uhblk", "\x2580"),
+  ("ulcorn", "\x231c"),
+  ("ulcorner", "\x231c"),
+  ("ulcrop", "\x230f"),
+  ("ultri", "\x25f8"),
+  ("umacr", "\x016b"),
+  ("um", "\x00a8"),
+  ("uml", "\x00a8"),
+  ("uogon", "\x0173"),
+  ("uopf", "\x1d566"),
+  ("uparrow", "\x2191"),
+  ("updownarrow", "\x2195"),
+  ("upharpoonleft", "\x21bf"),
+  ("upharpoonright", "\x21be"),
+  ("uplus", "\x228e"),
+  ("upsi", "\x03c5"),
+  ("upsih", "\x03d2"),
+  ("upsilon", "\x03c5"),
+  ("upuparrows", "\x21c8"),
+  ("urcorn", "\x231d"),
+  ("urcorner", "\x231d"),
+  ("urcrop", "\x230e"),
+  ("uring", "\x016f"),
+  ("urtri", "\x25f9"),
+  ("uscr", "\x1d4ca"),
+  ("utdot", "\x22f0"),
+  ("utilde", "\x0169"),
+  ("utri", "\x25b5"),
+  ("utrif", "\x25b4"),
+  ("uuarr", "\x21c8"),
+  ("uum", "\x00fc"),
+  ("uuml", "\x00fc"),
+  ("uwangle", "\x29a7"),
+  ("vArr", "\x21d5"),
+  ("vBar", "\x2ae8"),
+  ("vBarv", "\x2ae9"),
+  ("vDash", "\x22a8"),
+  ("vangrt", "\x299c"),
+  ("varepsilon", "\x03f5"),
+  ("varkappa", "\x03f0"),
+  ("varnothing", "\x2205"),
+  ("varphi", "\x03d5"),
+  ("varpi", "\x03d6"),
+  ("varpropto", "\x221d"),
+  ("varr", "\x2195"),
+  ("varrho", "\x03f1"),
+  ("varsigma", "\x03c2"),
+  ("varsubsetneq", "\x228a\xfe00"),
+  ("varsubsetneqq", "\x2acb\xfe00"),
+  ("varsupsetneq", "\x228b\xfe00"),
+  ("varsupsetneqq", "\x2acc\xfe00"),
+  ("vartheta", "\x03d1"),
+  ("vartriangleleft", "\x22b2"),
+  ("vartriangleright", "\x22b3"),
+  ("vcy", "\x0432"),
+  ("vdash", "\x22a2"),
+  ("vee", "\x2228"),
+  ("veebar", "\x22bb"),
+  ("veeeq", "\x225a"),
+  ("vellip", "\x22ee"),
+  ("verbar", "\x007c"),
+  ("vert", "\x007c"),
+  ("vfr", "\x1d533"),
+  ("vltri", "\x22b2"),
+  ("vnsub", "\x2282\x20d2"),
+  ("vnsup", "\x2283\x20d2"),
+  ("vopf", "\x1d567"),
+  ("vprop", "\x221d"),
+  ("vrtri", "\x22b3"),
+  ("vscr", "\x1d4cb"),
+  ("vsubnE", "\x2acb\xfe00"),
+  ("vsubne", "\x228a\xfe00"),
+  ("vsupnE", "\x2acc\xfe00"),
+  ("vsupne", "\x228b\xfe00"),
+  ("vzigzag", "\x299a"),
+  ("wcirc", "\x0175"),
+  ("wedbar", "\x2a5f"),
+  ("wedge", "\x2227"),
+  ("wedgeq", "\x2259"),
+  ("weierp", "\x2118"),
+  ("wfr", "\x1d534"),
+  ("wopf", "\x1d568"),
+  ("wp", "\x2118"),
+  ("wr", "\x2240"),
+  ("wreath", "\x2240"),
+  ("wscr", "\x1d4cc"),
+  ("xcap", "\x22c2"),
+  ("xcirc", "\x25ef"),
+  ("xcup", "\x22c3"),
+  ("xdtri", "\x25bd"),
+  ("xfr", "\x1d535"),
+  ("xhArr", "\x27fa"),
+  ("xharr", "\x27f7"),
+  ("xi", "\x03be"),
+  ("xlArr", "\x27f8"),
+  ("xlarr", "\x27f5"),
+  ("xmap", "\x27fc"),
+  ("xnis", "\x22fb"),
+  ("xodot", "\x2a00"),
+  ("xopf", "\x1d569"),
+  ("xoplus", "\x2a01"),
+  ("xotime", "\x2a02"),
+  ("xrArr", "\x27f9"),
+  ("xrarr", "\x27f6"),
+  ("xscr", "\x1d4cd"),
+  ("xsqcup", "\x2a06"),
+  ("xuplus", "\x2a04"),
+  ("xutri", "\x25b3"),
+  ("xvee", "\x22c1"),
+  ("xwedge", "\x22c0"),
+  ("yacut", "\x00fd"),
+  ("yacute", "\x00fd"),
+  ("yacy", "\x044f"),
+  ("ycirc", "\x0177"),
+  ("ycy", "\x044b"),
+  ("ye", "\x00a5"),
+  ("yen", "\x00a5"),
+  ("yfr", "\x1d536"),
+  ("yicy", "\x0457"),
+  ("yopf", "\x1d56a"),
+  ("yscr", "\x1d4ce"),
+  ("yucy", "\x044e"),
+  ("yum", "\x00ff"),
+  ("yuml", "\x00ff"),
+  ("zacute", "\x017a"),
+  ("zcaron", "\x017e"),
+  ("zcy", "\x0437"),
+  ("zdot", "\x017c"),
+  ("zeetrf", "\x2128"),
+  ("zeta", "\x03b6"),
+  ("zfr", "\x1d537"),
+  ("zhcy", "\x0436"),
+  ("zigrarr", "\x21dd"),
+  ("zopf", "\x1d56b"),
+  ("zscr", "\x1d4cf"),
+  ("zwj", "\x200d"),
+  ("zwnj", "\x200c")
+  ]
diff --git a/src/Text/HTML/Tree.hs b/src/Text/HTML/Tree.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/Tree.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE ViewPatterns          #-}
+
+module Text.HTML.Tree
+    ( -- * Constructing forests
+      tokensToForest
+    , ParseTokenForestError(..), PStack(..)
+    , nonClosing
+      -- * Deconstructing forests
+    , tokensFromForest
+    , tokensFromTree
+    ) where
+
+import           Data.Monoid
+import           Data.Text (Text)
+import           Data.Tree
+import           Prelude
+
+import           Text.HTML.Parser
+
+-- | construct a 'Forest' from a 'Token' list.
+--
+-- This code correctly handles void elements. Void elements are required to have a start tag and must not have an end tag. See 'nonClosing'.
+--
+-- This code does __not__ correctly handle optional tags. It assumes all optional start and end tags are present.
+--
+-- <https:\/\/www.w3.org\/TR\/html52\/syntax.html#optional-tags>
+tokensToForest :: [Token] -> Either ParseTokenForestError (Forest Token)
+tokensToForest = f (PStack [] [])
+  where
+    f (PStack ss []) [] = Right (reverse ss)
+    f pstack []         = Left $ ParseTokenForestErrorBracketMismatch pstack Nothing
+    f pstack (t : ts)   = case t of
+        TagOpen n _     -> if n `elem` nonClosing
+                             then f (pushFlatSibling t pstack) ts
+                             else f (pushParent t pstack) ts
+        TagSelfClose {} -> f (pushFlatSibling t pstack) ts
+        TagClose n      -> (`f` ts) =<< popParent n pstack
+        ContentChar _   -> f (pushFlatSibling t pstack) ts
+        ContentText _   -> f (pushFlatSibling t pstack) ts
+        Comment _       -> f (pushFlatSibling t pstack) ts
+        Doctype _       -> f (pushFlatSibling t pstack) ts
+
+-- | void elements which must not have an end tag
+--
+-- This list does not include the obsolete @\<command\>@ and @\<keygen\>@ elements.
+--
+-- @ nonClosing = ["br", "hr", "img", "meta", "area", "base", "col", "embed", "input", "link", "param", "source", "track", "wbr"] @
+--
+-- <https:\/\/www.w3.org\/TR\/html52\/syntax.html#void-elements>
+nonClosing :: [Text]
+nonClosing = ["br", "hr", "img", "meta", "area", "base", "col", "embed", "input", "link", "param", "source", "track", "wbr"]
+
+data ParseTokenForestError =
+    ParseTokenForestErrorBracketMismatch PStack (Maybe Token)
+  deriving (Eq, Show)
+
+data PStack = PStack
+    { _pstackToplevelSiblings :: Forest Token
+    , _pstackParents          :: [(Token, Forest Token)]
+    }
+  deriving (Eq, Show)
+
+pushParent :: Token -> PStack -> PStack
+pushParent t (PStack ss ps) = PStack [] ((t, ss) : ps)
+
+popParent :: TagName -> PStack -> Either ParseTokenForestError PStack
+popParent n (PStack ss ((p@(TagOpen n' _), ss') : ps))
+    | n == n' = Right $ PStack (Node p (reverse ss) : ss') ps
+popParent n pstack
+    = Left $ ParseTokenForestErrorBracketMismatch pstack (Just $ TagClose n)
+
+pushFlatSibling :: Token -> PStack -> PStack
+pushFlatSibling t (PStack ss ps) = PStack (Node t [] : ss) ps
+
+-- | convert a 'Forest' of 'Token' into a list of 'Token'.
+--
+-- This code correctly handles void elements. Void elements are required to have a start tag and must not have an end tag. See 'nonClosing'.
+tokensFromForest :: Forest Token -> [Token]
+tokensFromForest = mconcat . fmap tokensFromTree
+
+-- | convert a 'Tree' of 'Token' into a list of 'Token'.
+--
+-- This code correctly handles void elements. Void elements are required to have a start tag and must not have an end tag. See 'nonClosing'.
+tokensFromTree :: Tree Token -> [Token]
+tokensFromTree (Node o@(TagOpen n _) ts) | n `notElem` nonClosing
+    = [o] <> tokensFromForest ts <> [TagClose n]
+tokensFromTree (Node t [])
+    = [t]
+tokensFromTree _
+    = error "renderTokenTree: leaf node with children."
diff --git a/tests/Text/HTML/ParserSpec.hs b/tests/Text/HTML/ParserSpec.hs
--- a/tests/Text/HTML/ParserSpec.hs
+++ b/tests/Text/HTML/ParserSpec.hs
@@ -53,9 +53,9 @@
 
 -- FIXME: sometimes it is allowed to use '<' as text token, and we don't test that yet.  (whether we
 -- like this choice or not, we may want to follow the standard here.)  (same in tag names, attr
--- names.)
+-- names). We also avoid '&' since this may produce spurious character references.
 validXmlChar :: Gen Char
-validXmlChar = elements (['\x20'..'\x7E'] \\ "\x09\x0a\x0c /<>")
+validXmlChar = elements (['\x20'..'\x7E'] \\ "\x09\x0a\x0c &/<>")
 
 validXmlText :: Gen T.Text
 validXmlText = T.pack <$> sized (`maxListOf` validXmlChar)
@@ -63,7 +63,7 @@
 validXmlTagName :: Gen T.Text
 validXmlTagName = do
     initchar  <- elements $ ['a'..'z'] <> ['A'..'Z']
-    thenchars <- sized (`maxListOf` elements (['\x20'..'\x7E'] \\ "\x09\x0a\x0c /<>"))
+    thenchars <- sized (`maxListOf` elements (['\x20'..'\x7E'] \\ "\x09\x0a\x0c &/<>"))
     pure . T.pack $ initchar : thenchars
 
 validXmlAttrName :: Gen T.Text
@@ -90,7 +90,7 @@
 spec = do
   it "parseTokens and renderTokens are inverse" . property . forAllShrink arbitrary shrink $
     \(canonicalizeTokens -> tokens)
-      -> (parseTokens . TL.toStrict . renderTokens $ tokens) `shouldBe` tokens
+      -> (canonicalizeTokens . parseTokens . TL.toStrict . renderTokens $ tokens) `shouldBe` tokens
 
   it "canonicalizeTokens is idempotent" . property . forAllShrink arbitrary shrink $
     \tokens
@@ -108,3 +108,5 @@
         parseTokens "<!-- img src=\"/www_images/NCEP_GFS.gif\">" `shouldBe` [Comment " img src=\"/www_images/NCEP_GFS.gif\">"]
       it "parses funky comment" $ do
         parseTokens "<!-- img src=\"/www_images/NCEP_GFS.gif\"><!- -------------------------------------------------------- >" `shouldBe` [Comment " img src=\"/www_images/NCEP_GFS.gif\"><!- -------------------------------------------------------- >"]
+      it "parses entity" $ do
+        parseTokens "&lt;" `shouldBe` [ContentText "<"]
