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 +0/−406
- Text/HTML/Tree.hs +0/−71
- app/Main.hs +15/−0
- changelog.md +10/−0
- html-parse.cabal +22/−8
- src/Data/Trie.hs +34/−0
- src/Text/HTML/Parser.hs +430/−0
- src/Text/HTML/Parser/Entities.hs +2241/−0
- src/Text/HTML/Tree.hs +91/−0
- tests/Text/HTML/ParserSpec.hs +6/−4
− 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 "<" `shouldBe` [ContentText "<"]