packages feed

html-parse 0.2.0.2 → 0.2.1.0

raw patch · 10 files changed

+2849/−489 lines, 10 filesdep ~basedep ~containersdep ~deepseqnew-component:exe:html-parse-lengthPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, containers, deepseq, text

API changes (from Hackage documentation)

- Text.HTML.Tree: ParseTokenForestErrorBracketMismatch :: PStack -> (Maybe Token) -> ParseTokenForestError
+ Text.HTML.Tree: ParseTokenForestErrorBracketMismatch :: PStack -> Maybe Token -> ParseTokenForestError

Files

− Text/HTML/Parser.hs
@@ -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-      [] -> []
− Text/HTML/Tree.hs
@@ -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."
+ app/Main.hs view
@@ -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+
+ changelog.md view
@@ -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.
html-parse.cabal view
@@ -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
+ src/Data/Trie.hs view
@@ -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
+ src/Text/HTML/Parser.hs view
@@ -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+      [] -> []
+ src/Text/HTML/Parser/Entities.hs view
@@ -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")+  ]
+ src/Text/HTML/Tree.hs view
@@ -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."
tests/Text/HTML/ParserSpec.hs view
@@ -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 "<"]