From efd1a4f717afa83d3d3609f0d70e4da151a8dc9b Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Mon, 16 Sep 2024 14:00:23 +0200 Subject: [PATCH] [bugfix] Use better plaintext representation of status for filtering (#3301) * [bugfix] Use better plaintext representation of status for filtering * add new deps to readme * lint * update tests * update regexes * address review comments * remove now unused xxhash * whoops, wrong logger * Merge branch 'main' into status_filtering_bugfix * put cache in caches struct * pain --- README.md | 1 + go.mod | 1 + go.sum | 2 + internal/cache/cache.go | 20 + internal/gtsmodel/filter.go | 19 +- internal/typeutils/internaltofrontend.go | 87 +- internal/typeutils/internaltofrontend_test.go | 24 +- internal/typeutils/util.go | 62 + internal/typeutils/util_test.go | 60 + vendor/github.com/k3a/html2text/.travis.yml | 10 + vendor/github.com/k3a/html2text/LICENSE | 21 + vendor/github.com/k3a/html2text/README.md | 60 + vendor/github.com/k3a/html2text/entity.go | 2046 +++++++++++++++++ vendor/github.com/k3a/html2text/html2text.go | 333 +++ vendor/modules.txt | 3 + 15 files changed, 2685 insertions(+), 64 deletions(-) create mode 100644 vendor/github.com/k3a/html2text/.travis.yml create mode 100644 vendor/github.com/k3a/html2text/LICENSE create mode 100644 vendor/github.com/k3a/html2text/README.md create mode 100644 vendor/github.com/k3a/html2text/entity.go create mode 100644 vendor/github.com/k3a/html2text/html2text.go diff --git a/README.md b/README.md index 755a9f79f..989b7c1fa 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,7 @@ The following open source libraries, frameworks, and tools are used by GoToSocia - [jackc/pgconn](https://github.com/jackc/pgconn); Postgres driver. [MIT License](https://spdx.org/licenses/MIT.html). - [jackc/pgx](https://github.com/jackc/pgx); Postgres driver and toolkit. [MIT License](https://spdx.org/licenses/MIT.html). - [KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit); cgroups memory limit checking. [MIT License](https://spdx.org/licenses/MIT.html). +- [k3a/html2text](https://github.com/k3a/html2text); HTML-to-text conversion. [MIT License](https://spdx.org/licenses/MIT.html). - [mcuadros/go-syslog](https://github.com/mcuadros/go-syslog); Syslog server library. [MIT License](https://spdx.org/licenses/MIT.html). - [microcosm-cc/bluemonday](https://github.com/microcosm-cc/bluemonday); HTML user-input sanitization. [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html). - [miekg/dns](https://github.com/miekg/dns); DNS utilities. [Go License](https://go.dev/LICENSE). diff --git a/go.mod b/go.mod index e8bab31f4..a9a4afa84 100644 --- a/go.mod +++ b/go.mod @@ -40,6 +40,7 @@ require ( github.com/gorilla/feeds v1.2.0 github.com/gorilla/websocket v1.5.2 github.com/jackc/pgx/v5 v5.7.1 + github.com/k3a/html2text v1.2.1 github.com/microcosm-cc/bluemonday v1.0.27 github.com/miekg/dns v1.1.62 github.com/minio/minio-go/v7 v7.0.76 diff --git a/go.sum b/go.sum index 0dd75c4bb..8940bb3b2 100644 --- a/go.sum +++ b/go.sum @@ -384,6 +384,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/k3a/html2text v1.2.1 h1:nvnKgBvBR/myqrwfLuiqecUtaK1lB9hGziIJKatNFVY= +github.com/k3a/html2text v1.2.1/go.mod h1:ieEXykM67iT8lTvEWBh6fhpH4B23kB9OMKPdIBmgUqA= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 5554445b2..8291dec5a 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -47,6 +47,11 @@ type Caches struct { // Webfinger provides access to the webfinger URL cache. Webfinger *ttl.Cache[string, string] // TTL=24hr, sweep=5min + // TTL cache of statuses -> filterable text fields. + // To ensure up-to-date fields, cache is keyed as: + // `[status.ID][status.UpdatedAt.Unix()]` + StatusesFilterableFields *ttl.Cache[string, []string] + // prevent pass-by-value. _ nocopy } @@ -109,6 +114,7 @@ func (c *Caches) Init() { c.initUserMuteIDs() c.initWebfinger() c.initVisibility() + c.initStatusesFilterableFields() } // Start will start any caches that require a background @@ -119,6 +125,10 @@ func (c *Caches) Start() { tryUntil("starting webfinger cache", 5, func() bool { return c.Webfinger.Start(5 * time.Minute) }) + + tryUntil("starting statusesFilterableFields cache", 5, func() bool { + return c.StatusesFilterableFields.Start(5 * time.Minute) + }) } // Stop will stop any caches that require a background @@ -127,6 +137,7 @@ func (c *Caches) Stop() { log.Infof(nil, "stop: %p", c) tryUntil("stopping webfinger cache", 5, c.Webfinger.Stop) + tryUntil("stopping statusesFilterableFields cache", 5, c.StatusesFilterableFields.Stop) } // Sweep will sweep all the available caches to ensure none @@ -204,3 +215,12 @@ func (c *Caches) initWebfinger() { 24*time.Hour, ) } + +func (c *Caches) initStatusesFilterableFields() { + c.StatusesFilterableFields = new(ttl.Cache[string, []string]) + c.StatusesFilterableFields.Init( + 0, + 512, + 1*time.Hour, + ) +} diff --git a/internal/gtsmodel/filter.go b/internal/gtsmodel/filter.go index e670e6fc0..95047a44f 100644 --- a/internal/gtsmodel/filter.go +++ b/internal/gtsmodel/filter.go @@ -20,6 +20,8 @@ package gtsmodel import ( "regexp" "time" + + "github.com/superseriousbusiness/gotosocial/internal/util" ) // Filter stores a filter created by a local account. @@ -61,14 +63,23 @@ type FilterKeyword struct { // Compile will compile this FilterKeyword as a prepared regular expression. func (k *FilterKeyword) Compile() (err error) { - var wordBreak string - if k.WholeWord != nil && *k.WholeWord { - wordBreak = `\b` + var ( + wordBreakStart string + wordBreakEnd string + ) + + if util.PtrOrZero(k.WholeWord) { + // Either word boundary or + // whitespace or start of line. + wordBreakStart = `(?:\b|\s|^)` + // Either word boundary or + // whitespace or end of line. + wordBreakEnd = `(?:\b|\s|$)` } // Compile keyword filter regexp. quoted := regexp.QuoteMeta(k.Keyword) - k.Regexp, err = regexp.Compile(`(?i)` + wordBreak + quoted + wordBreak) + k.Regexp, err = regexp.Compile(`(?i)` + wordBreakStart + quoted + wordBreakEnd) return // caller is expected to wrap this error } diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go index 55af2c1f1..fe49766fa 100644 --- a/internal/typeutils/internaltofrontend.go +++ b/internal/typeutils/internaltofrontend.go @@ -21,6 +21,8 @@ import ( "context" "errors" "fmt" + "slices" + "strconv" "strings" "time" @@ -35,7 +37,6 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/language" "github.com/superseriousbusiness/gotosocial/internal/log" "github.com/superseriousbusiness/gotosocial/internal/media" - "github.com/superseriousbusiness/gotosocial/internal/text" "github.com/superseriousbusiness/gotosocial/internal/uris" "github.com/superseriousbusiness/gotosocial/internal/util" ) @@ -939,32 +940,48 @@ func (c *Converter) statusToAPIFilterResults( return nil, nil } - // Extract text fields from the status that we will match filters against. - fields := filterableTextFields(s) + // Key this status based on ID + last updated time, + // to ensure we always filter on latest version. + statusKey := s.ID + strconv.FormatInt(s.UpdatedAt.Unix(), 10) + + // Check if we have filterable fields cached for this status. + cache := c.state.Caches.StatusesFilterableFields + fields, stored := cache.Get(statusKey) + if !stored { + // We don't have filterable fields + // cached, calculate + cache now. + fields = filterableFields(s) + cache.Set(statusKey, fields) + } // Record all matching warn filters and the reasons they matched. filterResults := make([]apimodel.FilterResult, 0, len(filters)) for _, filter := range filters { if !filterAppliesInContext(filter, filterContext) { - // Filter doesn't apply to this context. - continue - } - if filter.Expired(now) { + // Filter doesn't apply + // to this context. continue } - // List all matching keywords. + if filter.Expired(now) { + // Filter doesn't + // apply anymore. + continue + } + + // Assemble matching keywords (if any) from this filter. keywordMatches := make([]string, 0, len(filter.Keywords)) - for _, filterKeyword := range filter.Keywords { - var isMatch bool - for _, field := range fields { - if filterKeyword.Regexp.MatchString(field) { - isMatch = true - break - } - } - if isMatch { - keywordMatches = append(keywordMatches, filterKeyword.Keyword) + for _, keyword := range filter.Keywords { + // Check if at least one filterable field + // in the status matches on this filter. + if slices.ContainsFunc( + fields, + func(field string) bool { + return keyword.Regexp.MatchString(field) + }, + ) { + // At least one field matched on this filter. + keywordMatches = append(keywordMatches, keyword.Keyword) } } @@ -1001,40 +1018,6 @@ func (c *Converter) statusToAPIFilterResults( return filterResults, nil } -// filterableTextFields returns all text from a status that we might want to filter on: -// - content -// - content warning -// - media descriptions -// - poll options -func filterableTextFields(s *gtsmodel.Status) []string { - fieldCount := 2 + len(s.Attachments) - if s.Poll != nil { - fieldCount += len(s.Poll.Options) - } - fields := make([]string, 0, fieldCount) - - if s.Content != "" { - fields = append(fields, text.SanitizeToPlaintext(s.Content)) - } - if s.ContentWarning != "" { - fields = append(fields, s.ContentWarning) - } - for _, attachment := range s.Attachments { - if attachment.Description != "" { - fields = append(fields, attachment.Description) - } - } - if s.Poll != nil { - for _, option := range s.Poll.Options { - if option != "" { - fields = append(fields, option) - } - } - } - - return fields -} - // filterAppliesInContext returns whether a given filter applies in a given context. func filterAppliesInContext(filter *gtsmodel.Filter, filterContext statusfilter.FilterContext) bool { switch filterContext { diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go index 651ff867d..a44afe67e 100644 --- a/internal/typeutils/internaltofrontend_test.go +++ b/internal/typeutils/internaltofrontend_test.go @@ -1063,15 +1063,21 @@ func (suite *InternalToFrontendTestSuite) TestHideFilteredBoostToFrontend() { // Test that a hashtag filter for a hashtag in Mastodon HTML content works the way most users would expect. func (suite *InternalToFrontendTestSuite) testHashtagFilteredStatusToFrontend(wholeWord bool, boost bool) { - testStatus := suite.testStatuses["admin_account_status_1"] + testStatus := new(gtsmodel.Status) + *testStatus = *suite.testStatuses["admin_account_status_1"] testStatus.Content = `

doggo doggin' it

#dogsofmastodon

` if boost { - // Modify a fixture boost into a boost of the above status. - boostStatus := suite.testStatuses["admin_account_status_4"] - boostStatus.BoostOf = testStatus - boostStatus.BoostOfID = testStatus.ID - testStatus = boostStatus + boost, err := suite.typeconverter.StatusToBoost( + context.Background(), + testStatus, + suite.testAccounts["admin_account"], + "", + ) + if err != nil { + suite.FailNow(err.Error()) + } + testStatus = boost } requestingAccount := suite.testAccounts["local_account_1"] @@ -1103,9 +1109,11 @@ func (suite *InternalToFrontendTestSuite) testHashtagFilteredStatusToFrontend(wh []*gtsmodel.Filter{filter}, nil, ) - if suite.NoError(err) { - suite.NotEmpty(apiStatus.Filtered) + if err != nil { + suite.FailNow(err.Error()) } + + suite.NotEmpty(apiStatus.Filtered) } func (suite *InternalToFrontendTestSuite) TestHashtagWholeWordFilteredStatusToFrontend() { diff --git a/internal/typeutils/util.go b/internal/typeutils/util.go index 3441e89a9..3a867ba35 100644 --- a/internal/typeutils/util.go +++ b/internal/typeutils/util.go @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/k3a/html2text" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/config" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" @@ -284,3 +285,64 @@ func ContentToContentLanguage( return contentStr, langTagStr } + +// filterableFields returns text fields from +// a status that we might want to filter on: +// +// - content warning +// - content (converted to plaintext from HTML) +// - media descriptions +// - poll options +// +// Each field should be filtered separately. +// This avoids scenarios where false-positive +// multiple-word matches can be made by matching +// the last word of one field + the first word +// of the next field together. +func filterableFields(s *gtsmodel.Status) []string { + // Estimate length of fields. + fieldCount := 2 + len(s.Attachments) + if s.Poll != nil { + fieldCount += len(s.Poll.Options) + } + fields := make([]string, 0, fieldCount) + + // Content warning / title. + if s.ContentWarning != "" { + fields = append(fields, s.ContentWarning) + } + + // Status content. Though we have raw text + // available for statuses created on our + // instance, use the html2text version to + // remove markdown-formatting characters + // and ensure more consistent filtering. + if s.Content != "" { + text := html2text.HTML2TextWithOptions( + s.Content, + html2text.WithLinksInnerText(), + html2text.WithUnixLineBreaks(), + ) + if text != "" { + fields = append(fields, text) + } + } + + // Media descriptions. + for _, attachment := range s.Attachments { + if attachment.Description != "" { + fields = append(fields, attachment.Description) + } + } + + // Poll options. + if s.Poll != nil { + for _, opt := range s.Poll.Options { + if opt != "" { + fields = append(fields, opt) + } + } + } + + return fields +} diff --git a/internal/typeutils/util_test.go b/internal/typeutils/util_test.go index 0f852d399..ea6667519 100644 --- a/internal/typeutils/util_test.go +++ b/internal/typeutils/util_test.go @@ -21,6 +21,7 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" "github.com/superseriousbusiness/gotosocial/internal/config" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/language" @@ -158,3 +159,62 @@ func TestContentToContentLanguage(t *testing.T) { } } } + +func TestFilterableText(t *testing.T) { + type testcase struct { + status *gtsmodel.Status + expectedFields []string + } + + for _, testcase := range []testcase{ + { + status: >smodel.Status{ + ContentWarning: "This is a test status", + Content: `

Import / export of account data via CSV files will be coming in 0.17.0 :) No more having to run scripts + CLI tools to import a list of accounts you follow, after doing a migration to a #GoToSocial instance.

`, + }, + expectedFields: []string{ + "This is a test status", + "Import / export of account data via CSV files will be coming in 0.17.0 :) No more having to run scripts + CLI tools to import a list of accounts you follow, after doing a migration to a #GoToSocial instance.", + }, + }, + { + status: >smodel.Status{ + Content: `

@zlatko currently we used modernc/sqlite3 for our sqlite driver, but we've been experimenting with wasm sqlite, and will likely move to that permanently in future; in the meantime, both options are available (the latter with a build tag)

https://github.com/superseriousbusiness/gotosocial/pull/2863

`, + }, + expectedFields: []string{ + "@zlatko currently we used modernc/sqlite3 for our sqlite driver, but we've been experimenting with wasm sqlite, and will likely move to that permanently in future; in the meantime, both options are available (the latter with a build tag)\n\nhttps://github.com/superseriousbusiness/gotosocial/pull/2863 ", + }, + }, + { + status: >smodel.Status{ + ContentWarning: "Nerd stuff", + Content: `

Latest graphs for #GoToSocial on Wasm sqlite3 with embedded Wasm ffmpeg, both running on Wazero, and configured with a 50MiB db cache target. This is the version we'll be releasing soonish, now we're happy with how we've tamed everything.

`, + Attachments: []*gtsmodel.MediaAttachment{ + { + Description: `Graph showing GtS using between 150-300 MiB of memory, steadily, over a few days.`, + }, + { + Description: `Another media attachment`, + }, + }, + Poll: >smodel.Poll{ + Options: []string{ + "Poll option 1", + "Poll option 2", + }, + }, + }, + expectedFields: []string{ + "Nerd stuff", + "Latest graphs for #GoToSocial on Wasm sqlite3 with embedded Wasm ffmpeg , both running on Wazero , and configured with a 50MiB db cache target . This is the version we'll be releasing soonish, now we're happy with how we've tamed everything.", + "Graph showing GtS using between 150-300 MiB of memory, steadily, over a few days.", + "Another media attachment", + "Poll option 1", + "Poll option 2", + }, + }, + } { + fields := filterableFields(testcase.status) + assert.Equal(t, testcase.expectedFields, fields) + } +} diff --git a/vendor/github.com/k3a/html2text/.travis.yml b/vendor/github.com/k3a/html2text/.travis.yml new file mode 100644 index 000000000..c9f214d59 --- /dev/null +++ b/vendor/github.com/k3a/html2text/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: + - master +before_install: + - go get github.com/axw/gocov/gocov + - go get github.com/mattn/goveralls + - if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi +script: + - $HOME/gopath/bin/goveralls -service=travis-ci + diff --git a/vendor/github.com/k3a/html2text/LICENSE b/vendor/github.com/k3a/html2text/LICENSE new file mode 100644 index 000000000..4838b48ab --- /dev/null +++ b/vendor/github.com/k3a/html2text/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Mario K3A Hros (www.k3a.me) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/k3a/html2text/README.md b/vendor/github.com/k3a/html2text/README.md new file mode 100644 index 000000000..892665905 --- /dev/null +++ b/vendor/github.com/k3a/html2text/README.md @@ -0,0 +1,60 @@ +[![GoDoc](https://godoc.org/github.com/k3a/html2text?status.svg)](https://godoc.org/github.com/k3a/html2text) +[![Build Status](https://travis-ci.org/k3a/html2text.svg?branch=master)](https://travis-ci.org/k3a/html2text) +[![Coverage Status](https://coveralls.io/repos/github/k3a/html2text/badge.svg?branch=master)](https://coveralls.io/github/k3a/html2text?branch=master) +[![Report Card](https://goreportcard.com/badge/github.com/k3a/html2text)](https://goreportcard.com/report/github.com/k3a/html2text) + +# html2text + +A simple Golang package to convert HTML to plain text (without non-standard dependencies). + +It converts HTML tags to text and also parses HTML entities into characters they represent. +A `` section of the HTML document, as well as most other tags are stripped out but +links are properly converted into their href attribute. + +It can be used for converting HTML emails into text. + +Some tests are installed as well. +Uses semantic versioning and no breaking changes are planned. + +Fell free to publish a pull request if you have suggestions for improvement but please note that the library can now be considered feature-complete and API stable. If you need more than this basic conversion, please use an alternative mentioned at the bottom. + +## Install +```bash +go get github.com/k3a/html2text +``` + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/k3a/html2text" +) + +func main() { + html := `Goodclean text` + + plain := html2text.HTML2Text(html) + + fmt.Println(plain) +} + +/* Outputs: + + clean text +*/ + +``` + +To see all features, please look info `html2text_test.go`. + +## Alternatives +- https://github.com/jaytaylor/html2text (heavier, with more features) +- https://git.alexwennerberg.com/nanohtml2text (rewrite of this module in Rust) + +## License + +MIT + diff --git a/vendor/github.com/k3a/html2text/entity.go b/vendor/github.com/k3a/html2text/entity.go new file mode 100644 index 000000000..68f90068d --- /dev/null +++ b/vendor/github.com/k3a/html2text/entity.go @@ -0,0 +1,2046 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html2text + +// entity is a map from HTML entity names to their values. The semicolon matters: +// https://html.spec.whatwg.org/multipage/named-characters.html +// lists both "amp" and "amp;" as two separate entries. +// +// Note that the HTML5 list is larger than the HTML4 list at +// http://www.w3.org/TR/html4/sgml/entities.html +var entity = map[string]rune{ + "AElig": '\U000000C6', + "AMP": '\U00000026', + "Aacute": '\U000000C1', + "Abreve": '\U00000102', + "Acirc": '\U000000C2', + "Acy": '\U00000410', + "Afr": '\U0001D504', + "Agrave": '\U000000C0', + "Alpha": '\U00000391', + "Amacr": '\U00000100', + "And": '\U00002A53', + "Aogon": '\U00000104', + "Aopf": '\U0001D538', + "ApplyFunction": '\U00002061', + "Aring": '\U000000C5', + "Ascr": '\U0001D49C', + "Assign": '\U00002254', + "Atilde": '\U000000C3', + "Auml": '\U000000C4', + "Backslash": '\U00002216', + "Barv": '\U00002AE7', + "Barwed": '\U00002306', + "Bcy": '\U00000411', + "Because": '\U00002235', + "Bernoullis": '\U0000212C', + "Beta": '\U00000392', + "Bfr": '\U0001D505', + "Bopf": '\U0001D539', + "Breve": '\U000002D8', + "Bscr": '\U0000212C', + "Bumpeq": '\U0000224E', + "CHcy": '\U00000427', + "COPY": '\U000000A9', + "Cacute": '\U00000106', + "Cap": '\U000022D2', + "CapitalDifferentialD": '\U00002145', + "Cayleys": '\U0000212D', + "Ccaron": '\U0000010C', + "Ccedil": '\U000000C7', + "Ccirc": '\U00000108', + "Cconint": '\U00002230', + "Cdot": '\U0000010A', + "Cedilla": '\U000000B8', + "CenterDot": '\U000000B7', + "Cfr": '\U0000212D', + "Chi": '\U000003A7', + "CircleDot": '\U00002299', + "CircleMinus": '\U00002296', + "CirclePlus": '\U00002295', + "CircleTimes": '\U00002297', + "ClockwiseContourIntegral": '\U00002232', + "CloseCurlyDoubleQuote": '\U0000201D', + "CloseCurlyQuote": '\U00002019', + "Colon": '\U00002237', + "Colone": '\U00002A74', + "Congruent": '\U00002261', + "Conint": '\U0000222F', + "ContourIntegral": '\U0000222E', + "Copf": '\U00002102', + "Coproduct": '\U00002210', + "CounterClockwiseContourIntegral": '\U00002233', + "Cross": '\U00002A2F', + "Cscr": '\U0001D49E', + "Cup": '\U000022D3', + "CupCap": '\U0000224D', + "DD": '\U00002145', + "DDotrahd": '\U00002911', + "DJcy": '\U00000402', + "DScy": '\U00000405', + "DZcy": '\U0000040F', + "Dagger": '\U00002021', + "Darr": '\U000021A1', + "Dashv": '\U00002AE4', + "Dcaron": '\U0000010E', + "Dcy": '\U00000414', + "Del": '\U00002207', + "Delta": '\U00000394', + "Dfr": '\U0001D507', + "DiacriticalAcute": '\U000000B4', + "DiacriticalDot": '\U000002D9', + "DiacriticalDoubleAcute": '\U000002DD', + "DiacriticalGrave": '\U00000060', + "DiacriticalTilde": '\U000002DC', + "Diamond": '\U000022C4', + "DifferentialD": '\U00002146', + "Dopf": '\U0001D53B', + "Dot": '\U000000A8', + "DotDot": '\U000020DC', + "DotEqual": '\U00002250', + "DoubleContourIntegral": '\U0000222F', + "DoubleDot": '\U000000A8', + "DoubleDownArrow": '\U000021D3', + "DoubleLeftArrow": '\U000021D0', + "DoubleLeftRightArrow": '\U000021D4', + "DoubleLeftTee": '\U00002AE4', + "DoubleLongLeftArrow": '\U000027F8', + "DoubleLongLeftRightArrow": '\U000027FA', + "DoubleLongRightArrow": '\U000027F9', + "DoubleRightArrow": '\U000021D2', + "DoubleRightTee": '\U000022A8', + "DoubleUpArrow": '\U000021D1', + "DoubleUpDownArrow": '\U000021D5', + "DoubleVerticalBar": '\U00002225', + "DownArrow": '\U00002193', + "DownArrowBar": '\U00002913', + "DownArrowUpArrow": '\U000021F5', + "DownBreve": '\U00000311', + "DownLeftRightVector": '\U00002950', + "DownLeftTeeVector": '\U0000295E', + "DownLeftVector": '\U000021BD', + "DownLeftVectorBar": '\U00002956', + "DownRightTeeVector": '\U0000295F', + "DownRightVector": '\U000021C1', + "DownRightVectorBar": '\U00002957', + "DownTee": '\U000022A4', + "DownTeeArrow": '\U000021A7', + "Downarrow": '\U000021D3', + "Dscr": '\U0001D49F', + "Dstrok": '\U00000110', + "ENG": '\U0000014A', + "ETH": '\U000000D0', + "Eacute": '\U000000C9', + "Ecaron": '\U0000011A', + "Ecirc": '\U000000CA', + "Ecy": '\U0000042D', + "Edot": '\U00000116', + "Efr": '\U0001D508', + "Egrave": '\U000000C8', + "Element": '\U00002208', + "Emacr": '\U00000112', + "EmptySmallSquare": '\U000025FB', + "EmptyVerySmallSquare": '\U000025AB', + "Eogon": '\U00000118', + "Eopf": '\U0001D53C', + "Epsilon": '\U00000395', + "Equal": '\U00002A75', + "EqualTilde": '\U00002242', + "Equilibrium": '\U000021CC', + "Escr": '\U00002130', + "Esim": '\U00002A73', + "Eta": '\U00000397', + "Euml": '\U000000CB', + "Exists": '\U00002203', + "ExponentialE": '\U00002147', + "Fcy": '\U00000424', + "Ffr": '\U0001D509', + "FilledSmallSquare": '\U000025FC', + "FilledVerySmallSquare": '\U000025AA', + "Fopf": '\U0001D53D', + "ForAll": '\U00002200', + "Fouriertrf": '\U00002131', + "Fscr": '\U00002131', + "GJcy": '\U00000403', + "GT": '\U0000003E', + "Gamma": '\U00000393', + "Gammad": '\U000003DC', + "Gbreve": '\U0000011E', + "Gcedil": '\U00000122', + "Gcirc": '\U0000011C', + "Gcy": '\U00000413', + "Gdot": '\U00000120', + "Gfr": '\U0001D50A', + "Gg": '\U000022D9', + "Gopf": '\U0001D53E', + "GreaterEqual": '\U00002265', + "GreaterEqualLess": '\U000022DB', + "GreaterFullEqual": '\U00002267', + "GreaterGreater": '\U00002AA2', + "GreaterLess": '\U00002277', + "GreaterSlantEqual": '\U00002A7E', + "GreaterTilde": '\U00002273', + "Gscr": '\U0001D4A2', + "Gt": '\U0000226B', + "HARDcy": '\U0000042A', + "Hacek": '\U000002C7', + "Hat": '\U0000005E', + "Hcirc": '\U00000124', + "Hfr": '\U0000210C', + "HilbertSpace": '\U0000210B', + "Hopf": '\U0000210D', + "HorizontalLine": '\U00002500', + "Hscr": '\U0000210B', + "Hstrok": '\U00000126', + "HumpDownHump": '\U0000224E', + "HumpEqual": '\U0000224F', + "IEcy": '\U00000415', + "IJlig": '\U00000132', + "IOcy": '\U00000401', + "Iacute": '\U000000CD', + "Icirc": '\U000000CE', + "Icy": '\U00000418', + "Idot": '\U00000130', + "Ifr": '\U00002111', + "Igrave": '\U000000CC', + "Im": '\U00002111', + "Imacr": '\U0000012A', + "ImaginaryI": '\U00002148', + "Implies": '\U000021D2', + "Int": '\U0000222C', + "Integral": '\U0000222B', + "Intersection": '\U000022C2', + "InvisibleComma": '\U00002063', + "InvisibleTimes": '\U00002062', + "Iogon": '\U0000012E', + "Iopf": '\U0001D540', + "Iota": '\U00000399', + "Iscr": '\U00002110', + "Itilde": '\U00000128', + "Iukcy": '\U00000406', + "Iuml": '\U000000CF', + "Jcirc": '\U00000134', + "Jcy": '\U00000419', + "Jfr": '\U0001D50D', + "Jopf": '\U0001D541', + "Jscr": '\U0001D4A5', + "Jsercy": '\U00000408', + "Jukcy": '\U00000404', + "KHcy": '\U00000425', + "KJcy": '\U0000040C', + "Kappa": '\U0000039A', + "Kcedil": '\U00000136', + "Kcy": '\U0000041A', + "Kfr": '\U0001D50E', + "Kopf": '\U0001D542', + "Kscr": '\U0001D4A6', + "LJcy": '\U00000409', + "LT": '\U0000003C', + "Lacute": '\U00000139', + "Lambda": '\U0000039B', + "Lang": '\U000027EA', + "Laplacetrf": '\U00002112', + "Larr": '\U0000219E', + "Lcaron": '\U0000013D', + "Lcedil": '\U0000013B', + "Lcy": '\U0000041B', + "LeftAngleBracket": '\U000027E8', + "LeftArrow": '\U00002190', + "LeftArrowBar": '\U000021E4', + "LeftArrowRightArrow": '\U000021C6', + "LeftCeiling": '\U00002308', + "LeftDoubleBracket": '\U000027E6', + "LeftDownTeeVector": '\U00002961', + "LeftDownVector": '\U000021C3', + "LeftDownVectorBar": '\U00002959', + "LeftFloor": '\U0000230A', + "LeftRightArrow": '\U00002194', + "LeftRightVector": '\U0000294E', + "LeftTee": '\U000022A3', + "LeftTeeArrow": '\U000021A4', + "LeftTeeVector": '\U0000295A', + "LeftTriangle": '\U000022B2', + "LeftTriangleBar": '\U000029CF', + "LeftTriangleEqual": '\U000022B4', + "LeftUpDownVector": '\U00002951', + "LeftUpTeeVector": '\U00002960', + "LeftUpVector": '\U000021BF', + "LeftUpVectorBar": '\U00002958', + "LeftVector": '\U000021BC', + "LeftVectorBar": '\U00002952', + "Leftarrow": '\U000021D0', + "Leftrightarrow": '\U000021D4', + "LessEqualGreater": '\U000022DA', + "LessFullEqual": '\U00002266', + "LessGreater": '\U00002276', + "LessLess": '\U00002AA1', + "LessSlantEqual": '\U00002A7D', + "LessTilde": '\U00002272', + "Lfr": '\U0001D50F', + "Ll": '\U000022D8', + "Lleftarrow": '\U000021DA', + "Lmidot": '\U0000013F', + "LongLeftArrow": '\U000027F5', + "LongLeftRightArrow": '\U000027F7', + "LongRightArrow": '\U000027F6', + "Longleftarrow": '\U000027F8', + "Longleftrightarrow": '\U000027FA', + "Longrightarrow": '\U000027F9', + "Lopf": '\U0001D543', + "LowerLeftArrow": '\U00002199', + "LowerRightArrow": '\U00002198', + "Lscr": '\U00002112', + "Lsh": '\U000021B0', + "Lstrok": '\U00000141', + "Lt": '\U0000226A', + "Map": '\U00002905', + "Mcy": '\U0000041C', + "MediumSpace": '\U0000205F', + "Mellintrf": '\U00002133', + "Mfr": '\U0001D510', + "MinusPlus": '\U00002213', + "Mopf": '\U0001D544', + "Mscr": '\U00002133', + "Mu": '\U0000039C', + "NJcy": '\U0000040A', + "Nacute": '\U00000143', + "Ncaron": '\U00000147', + "Ncedil": '\U00000145', + "Ncy": '\U0000041D', + "NegativeMediumSpace": '\U0000200B', + "NegativeThickSpace": '\U0000200B', + "NegativeThinSpace": '\U0000200B', + "NegativeVeryThinSpace": '\U0000200B', + "NestedGreaterGreater": '\U0000226B', + "NestedLessLess": '\U0000226A', + "NewLine": '\U0000000A', + "Nfr": '\U0001D511', + "NoBreak": '\U00002060', + "NonBreakingSpace": '\U000000A0', + "Nopf": '\U00002115', + "Not": '\U00002AEC', + "NotCongruent": '\U00002262', + "NotCupCap": '\U0000226D', + "NotDoubleVerticalBar": '\U00002226', + "NotElement": '\U00002209', + "NotEqual": '\U00002260', + "NotExists": '\U00002204', + "NotGreater": '\U0000226F', + "NotGreaterEqual": '\U00002271', + "NotGreaterLess": '\U00002279', + "NotGreaterTilde": '\U00002275', + "NotLeftTriangle": '\U000022EA', + "NotLeftTriangleEqual": '\U000022EC', + "NotLess": '\U0000226E', + "NotLessEqual": '\U00002270', + "NotLessGreater": '\U00002278', + "NotLessTilde": '\U00002274', + "NotPrecedes": '\U00002280', + "NotPrecedesSlantEqual": '\U000022E0', + "NotReverseElement": '\U0000220C', + "NotRightTriangle": '\U000022EB', + "NotRightTriangleEqual": '\U000022ED', + "NotSquareSubsetEqual": '\U000022E2', + "NotSquareSupersetEqual": '\U000022E3', + "NotSubsetEqual": '\U00002288', + "NotSucceeds": '\U00002281', + "NotSucceedsSlantEqual": '\U000022E1', + "NotSupersetEqual": '\U00002289', + "NotTilde": '\U00002241', + "NotTildeEqual": '\U00002244', + "NotTildeFullEqual": '\U00002247', + "NotTildeTilde": '\U00002249', + "NotVerticalBar": '\U00002224', + "Nscr": '\U0001D4A9', + "Ntilde": '\U000000D1', + "Nu": '\U0000039D', + "OElig": '\U00000152', + "Oacute": '\U000000D3', + "Ocirc": '\U000000D4', + "Ocy": '\U0000041E', + "Odblac": '\U00000150', + "Ofr": '\U0001D512', + "Ograve": '\U000000D2', + "Omacr": '\U0000014C', + "Omega": '\U000003A9', + "Omicron": '\U0000039F', + "Oopf": '\U0001D546', + "OpenCurlyDoubleQuote": '\U0000201C', + "OpenCurlyQuote": '\U00002018', + "Or": '\U00002A54', + "Oscr": '\U0001D4AA', + "Oslash": '\U000000D8', + "Otilde": '\U000000D5', + "Otimes": '\U00002A37', + "Ouml": '\U000000D6', + "OverBar": '\U0000203E', + "OverBrace": '\U000023DE', + "OverBracket": '\U000023B4', + "OverParenthesis": '\U000023DC', + "PartialD": '\U00002202', + "Pcy": '\U0000041F', + "Pfr": '\U0001D513', + "Phi": '\U000003A6', + "Pi": '\U000003A0', + "PlusMinus": '\U000000B1', + "Poincareplane": '\U0000210C', + "Popf": '\U00002119', + "Pr": '\U00002ABB', + "Precedes": '\U0000227A', + "PrecedesEqual": '\U00002AAF', + "PrecedesSlantEqual": '\U0000227C', + "PrecedesTilde": '\U0000227E', + "Prime": '\U00002033', + "Product": '\U0000220F', + "Proportion": '\U00002237', + "Proportional": '\U0000221D', + "Pscr": '\U0001D4AB', + "Psi": '\U000003A8', + "QUOT": '\U00000022', + "Qfr": '\U0001D514', + "Qopf": '\U0000211A', + "Qscr": '\U0001D4AC', + "RBarr": '\U00002910', + "REG": '\U000000AE', + "Racute": '\U00000154', + "Rang": '\U000027EB', + "Rarr": '\U000021A0', + "Rarrtl": '\U00002916', + "Rcaron": '\U00000158', + "Rcedil": '\U00000156', + "Rcy": '\U00000420', + "Re": '\U0000211C', + "ReverseElement": '\U0000220B', + "ReverseEquilibrium": '\U000021CB', + "ReverseUpEquilibrium": '\U0000296F', + "Rfr": '\U0000211C', + "Rho": '\U000003A1', + "RightAngleBracket": '\U000027E9', + "RightArrow": '\U00002192', + "RightArrowBar": '\U000021E5', + "RightArrowLeftArrow": '\U000021C4', + "RightCeiling": '\U00002309', + "RightDoubleBracket": '\U000027E7', + "RightDownTeeVector": '\U0000295D', + "RightDownVector": '\U000021C2', + "RightDownVectorBar": '\U00002955', + "RightFloor": '\U0000230B', + "RightTee": '\U000022A2', + "RightTeeArrow": '\U000021A6', + "RightTeeVector": '\U0000295B', + "RightTriangle": '\U000022B3', + "RightTriangleBar": '\U000029D0', + "RightTriangleEqual": '\U000022B5', + "RightUpDownVector": '\U0000294F', + "RightUpTeeVector": '\U0000295C', + "RightUpVector": '\U000021BE', + "RightUpVectorBar": '\U00002954', + "RightVector": '\U000021C0', + "RightVectorBar": '\U00002953', + "Rightarrow": '\U000021D2', + "Ropf": '\U0000211D', + "RoundImplies": '\U00002970', + "Rrightarrow": '\U000021DB', + "Rscr": '\U0000211B', + "Rsh": '\U000021B1', + "RuleDelayed": '\U000029F4', + "SHCHcy": '\U00000429', + "SHcy": '\U00000428', + "SOFTcy": '\U0000042C', + "Sacute": '\U0000015A', + "Sc": '\U00002ABC', + "Scaron": '\U00000160', + "Scedil": '\U0000015E', + "Scirc": '\U0000015C', + "Scy": '\U00000421', + "Sfr": '\U0001D516', + "ShortDownArrow": '\U00002193', + "ShortLeftArrow": '\U00002190', + "ShortRightArrow": '\U00002192', + "ShortUpArrow": '\U00002191', + "Sigma": '\U000003A3', + "SmallCircle": '\U00002218', + "Sopf": '\U0001D54A', + "Sqrt": '\U0000221A', + "Square": '\U000025A1', + "SquareIntersection": '\U00002293', + "SquareSubset": '\U0000228F', + "SquareSubsetEqual": '\U00002291', + "SquareSuperset": '\U00002290', + "SquareSupersetEqual": '\U00002292', + "SquareUnion": '\U00002294', + "Sscr": '\U0001D4AE', + "Star": '\U000022C6', + "Sub": '\U000022D0', + "Subset": '\U000022D0', + "SubsetEqual": '\U00002286', + "Succeeds": '\U0000227B', + "SucceedsEqual": '\U00002AB0', + "SucceedsSlantEqual": '\U0000227D', + "SucceedsTilde": '\U0000227F', + "SuchThat": '\U0000220B', + "Sum": '\U00002211', + "Sup": '\U000022D1', + "Superset": '\U00002283', + "SupersetEqual": '\U00002287', + "Supset": '\U000022D1', + "THORN": '\U000000DE', + "TRADE": '\U00002122', + "TSHcy": '\U0000040B', + "TScy": '\U00000426', + "Tab": '\U00000009', + "Tau": '\U000003A4', + "Tcaron": '\U00000164', + "Tcedil": '\U00000162', + "Tcy": '\U00000422', + "Tfr": '\U0001D517', + "Therefore": '\U00002234', + "Theta": '\U00000398', + "ThinSpace": '\U00002009', + "Tilde": '\U0000223C', + "TildeEqual": '\U00002243', + "TildeFullEqual": '\U00002245', + "TildeTilde": '\U00002248', + "Topf": '\U0001D54B', + "TripleDot": '\U000020DB', + "Tscr": '\U0001D4AF', + "Tstrok": '\U00000166', + "Uacute": '\U000000DA', + "Uarr": '\U0000219F', + "Uarrocir": '\U00002949', + "Ubrcy": '\U0000040E', + "Ubreve": '\U0000016C', + "Ucirc": '\U000000DB', + "Ucy": '\U00000423', + "Udblac": '\U00000170', + "Ufr": '\U0001D518', + "Ugrave": '\U000000D9', + "Umacr": '\U0000016A', + "UnderBar": '\U0000005F', + "UnderBrace": '\U000023DF', + "UnderBracket": '\U000023B5', + "UnderParenthesis": '\U000023DD', + "Union": '\U000022C3', + "UnionPlus": '\U0000228E', + "Uogon": '\U00000172', + "Uopf": '\U0001D54C', + "UpArrow": '\U00002191', + "UpArrowBar": '\U00002912', + "UpArrowDownArrow": '\U000021C5', + "UpDownArrow": '\U00002195', + "UpEquilibrium": '\U0000296E', + "UpTee": '\U000022A5', + "UpTeeArrow": '\U000021A5', + "Uparrow": '\U000021D1', + "Updownarrow": '\U000021D5', + "UpperLeftArrow": '\U00002196', + "UpperRightArrow": '\U00002197', + "Upsi": '\U000003D2', + "Upsilon": '\U000003A5', + "Uring": '\U0000016E', + "Uscr": '\U0001D4B0', + "Utilde": '\U00000168', + "Uuml": '\U000000DC', + "VDash": '\U000022AB', + "Vbar": '\U00002AEB', + "Vcy": '\U00000412', + "Vdash": '\U000022A9', + "Vdashl": '\U00002AE6', + "Vee": '\U000022C1', + "Verbar": '\U00002016', + "Vert": '\U00002016', + "VerticalBar": '\U00002223', + "VerticalLine": '\U0000007C', + "VerticalSeparator": '\U00002758', + "VerticalTilde": '\U00002240', + "VeryThinSpace": '\U0000200A', + "Vfr": '\U0001D519', + "Vopf": '\U0001D54D', + "Vscr": '\U0001D4B1', + "Vvdash": '\U000022AA', + "Wcirc": '\U00000174', + "Wedge": '\U000022C0', + "Wfr": '\U0001D51A', + "Wopf": '\U0001D54E', + "Wscr": '\U0001D4B2', + "Xfr": '\U0001D51B', + "Xi": '\U0000039E', + "Xopf": '\U0001D54F', + "Xscr": '\U0001D4B3', + "YAcy": '\U0000042F', + "YIcy": '\U00000407', + "YUcy": '\U0000042E', + "Yacute": '\U000000DD', + "Ycirc": '\U00000176', + "Ycy": '\U0000042B', + "Yfr": '\U0001D51C', + "Yopf": '\U0001D550', + "Yscr": '\U0001D4B4', + "Yuml": '\U00000178', + "ZHcy": '\U00000416', + "Zacute": '\U00000179', + "Zcaron": '\U0000017D', + "Zcy": '\U00000417', + "Zdot": '\U0000017B', + "ZeroWidthSpace": '\U0000200B', + "Zeta": '\U00000396', + "Zfr": '\U00002128', + "Zopf": '\U00002124', + "Zscr": '\U0001D4B5', + "aacute": '\U000000E1', + "abreve": '\U00000103', + "ac": '\U0000223E', + "acd": '\U0000223F', + "acirc": '\U000000E2', + "acute": '\U000000B4', + "acy": '\U00000430', + "aelig": '\U000000E6', + "af": '\U00002061', + "afr": '\U0001D51E', + "agrave": '\U000000E0', + "alefsym": '\U00002135', + "aleph": '\U00002135', + "alpha": '\U000003B1', + "amacr": '\U00000101', + "amalg": '\U00002A3F', + "amp": '\U00000026', + "and": '\U00002227', + "andand": '\U00002A55', + "andd": '\U00002A5C', + "andslope": '\U00002A58', + "andv": '\U00002A5A', + "ang": '\U00002220', + "ange": '\U000029A4', + "angle": '\U00002220', + "angmsd": '\U00002221', + "angmsdaa": '\U000029A8', + "angmsdab": '\U000029A9', + "angmsdac": '\U000029AA', + "angmsdad": '\U000029AB', + "angmsdae": '\U000029AC', + "angmsdaf": '\U000029AD', + "angmsdag": '\U000029AE', + "angmsdah": '\U000029AF', + "angrt": '\U0000221F', + "angrtvb": '\U000022BE', + "angrtvbd": '\U0000299D', + "angsph": '\U00002222', + "angst": '\U000000C5', + "angzarr": '\U0000237C', + "aogon": '\U00000105', + "aopf": '\U0001D552', + "ap": '\U00002248', + "apE": '\U00002A70', + "apacir": '\U00002A6F', + "ape": '\U0000224A', + "apid": '\U0000224B', + "apos": '\U00000027', + "approx": '\U00002248', + "approxeq": '\U0000224A', + "aring": '\U000000E5', + "ascr": '\U0001D4B6', + "ast": '\U0000002A', + "asymp": '\U00002248', + "asympeq": '\U0000224D', + "atilde": '\U000000E3', + "auml": '\U000000E4', + "awconint": '\U00002233', + "awint": '\U00002A11', + "bNot": '\U00002AED', + "backcong": '\U0000224C', + "backepsilon": '\U000003F6', + "backprime": '\U00002035', + "backsim": '\U0000223D', + "backsimeq": '\U000022CD', + "barvee": '\U000022BD', + "barwed": '\U00002305', + "barwedge": '\U00002305', + "bbrk": '\U000023B5', + "bbrktbrk": '\U000023B6', + "bcong": '\U0000224C', + "bcy": '\U00000431', + "bdquo": '\U0000201E', + "becaus": '\U00002235', + "because": '\U00002235', + "bemptyv": '\U000029B0', + "bepsi": '\U000003F6', + "bernou": '\U0000212C', + "beta": '\U000003B2', + "beth": '\U00002136', + "between": '\U0000226C', + "bfr": '\U0001D51F', + "bigcap": '\U000022C2', + "bigcirc": '\U000025EF', + "bigcup": '\U000022C3', + "bigodot": '\U00002A00', + "bigoplus": '\U00002A01', + "bigotimes": '\U00002A02', + "bigsqcup": '\U00002A06', + "bigstar": '\U00002605', + "bigtriangledown": '\U000025BD', + "bigtriangleup": '\U000025B3', + "biguplus": '\U00002A04', + "bigvee": '\U000022C1', + "bigwedge": '\U000022C0', + "bkarow": '\U0000290D', + "blacklozenge": '\U000029EB', + "blacksquare": '\U000025AA', + "blacktriangle": '\U000025B4', + "blacktriangledown": '\U000025BE', + "blacktriangleleft": '\U000025C2', + "blacktriangleright": '\U000025B8', + "blank": '\U00002423', + "blk12": '\U00002592', + "blk14": '\U00002591', + "blk34": '\U00002593', + "block": '\U00002588', + "bnot": '\U00002310', + "bopf": '\U0001D553', + "bot": '\U000022A5', + "bottom": '\U000022A5', + "bowtie": '\U000022C8', + "boxDL": '\U00002557', + "boxDR": '\U00002554', + "boxDl": '\U00002556', + "boxDr": '\U00002553', + "boxH": '\U00002550', + "boxHD": '\U00002566', + "boxHU": '\U00002569', + "boxHd": '\U00002564', + "boxHu": '\U00002567', + "boxUL": '\U0000255D', + "boxUR": '\U0000255A', + "boxUl": '\U0000255C', + "boxUr": '\U00002559', + "boxV": '\U00002551', + "boxVH": '\U0000256C', + "boxVL": '\U00002563', + "boxVR": '\U00002560', + "boxVh": '\U0000256B', + "boxVl": '\U00002562', + "boxVr": '\U0000255F', + "boxbox": '\U000029C9', + "boxdL": '\U00002555', + "boxdR": '\U00002552', + "boxdl": '\U00002510', + "boxdr": '\U0000250C', + "boxh": '\U00002500', + "boxhD": '\U00002565', + "boxhU": '\U00002568', + "boxhd": '\U0000252C', + "boxhu": '\U00002534', + "boxminus": '\U0000229F', + "boxplus": '\U0000229E', + "boxtimes": '\U000022A0', + "boxuL": '\U0000255B', + "boxuR": '\U00002558', + "boxul": '\U00002518', + "boxur": '\U00002514', + "boxv": '\U00002502', + "boxvH": '\U0000256A', + "boxvL": '\U00002561', + "boxvR": '\U0000255E', + "boxvh": '\U0000253C', + "boxvl": '\U00002524', + "boxvr": '\U0000251C', + "bprime": '\U00002035', + "breve": '\U000002D8', + "brvbar": '\U000000A6', + "bscr": '\U0001D4B7', + "bsemi": '\U0000204F', + "bsim": '\U0000223D', + "bsime": '\U000022CD', + "bsol": '\U0000005C', + "bsolb": '\U000029C5', + "bsolhsub": '\U000027C8', + "bull": '\U00002022', + "bullet": '\U00002022', + "bump": '\U0000224E', + "bumpE": '\U00002AAE', + "bumpe": '\U0000224F', + "bumpeq": '\U0000224F', + "cacute": '\U00000107', + "cap": '\U00002229', + "capand": '\U00002A44', + "capbrcup": '\U00002A49', + "capcap": '\U00002A4B', + "capcup": '\U00002A47', + "capdot": '\U00002A40', + "caret": '\U00002041', + "caron": '\U000002C7', + "ccaps": '\U00002A4D', + "ccaron": '\U0000010D', + "ccedil": '\U000000E7', + "ccirc": '\U00000109', + "ccups": '\U00002A4C', + "ccupssm": '\U00002A50', + "cdot": '\U0000010B', + "cedil": '\U000000B8', + "cemptyv": '\U000029B2', + "cent": '\U000000A2', + "centerdot": '\U000000B7', + "cfr": '\U0001D520', + "chcy": '\U00000447', + "check": '\U00002713', + "checkmark": '\U00002713', + "chi": '\U000003C7', + "cir": '\U000025CB', + "cirE": '\U000029C3', + "circ": '\U000002C6', + "circeq": '\U00002257', + "circlearrowleft": '\U000021BA', + "circlearrowright": '\U000021BB', + "circledR": '\U000000AE', + "circledS": '\U000024C8', + "circledast": '\U0000229B', + "circledcirc": '\U0000229A', + "circleddash": '\U0000229D', + "cire": '\U00002257', + "cirfnint": '\U00002A10', + "cirmid": '\U00002AEF', + "cirscir": '\U000029C2', + "clubs": '\U00002663', + "clubsuit": '\U00002663', + "colon": '\U0000003A', + "colone": '\U00002254', + "coloneq": '\U00002254', + "comma": '\U0000002C', + "commat": '\U00000040', + "comp": '\U00002201', + "compfn": '\U00002218', + "complement": '\U00002201', + "complexes": '\U00002102', + "cong": '\U00002245', + "congdot": '\U00002A6D', + "conint": '\U0000222E', + "copf": '\U0001D554', + "coprod": '\U00002210', + "copy": '\U000000A9', + "copysr": '\U00002117', + "crarr": '\U000021B5', + "cross": '\U00002717', + "cscr": '\U0001D4B8', + "csub": '\U00002ACF', + "csube": '\U00002AD1', + "csup": '\U00002AD0', + "csupe": '\U00002AD2', + "ctdot": '\U000022EF', + "cudarrl": '\U00002938', + "cudarrr": '\U00002935', + "cuepr": '\U000022DE', + "cuesc": '\U000022DF', + "cularr": '\U000021B6', + "cularrp": '\U0000293D', + "cup": '\U0000222A', + "cupbrcap": '\U00002A48', + "cupcap": '\U00002A46', + "cupcup": '\U00002A4A', + "cupdot": '\U0000228D', + "cupor": '\U00002A45', + "curarr": '\U000021B7', + "curarrm": '\U0000293C', + "curlyeqprec": '\U000022DE', + "curlyeqsucc": '\U000022DF', + "curlyvee": '\U000022CE', + "curlywedge": '\U000022CF', + "curren": '\U000000A4', + "curvearrowleft": '\U000021B6', + "curvearrowright": '\U000021B7', + "cuvee": '\U000022CE', + "cuwed": '\U000022CF', + "cwconint": '\U00002232', + "cwint": '\U00002231', + "cylcty": '\U0000232D', + "dArr": '\U000021D3', + "dHar": '\U00002965', + "dagger": '\U00002020', + "daleth": '\U00002138', + "darr": '\U00002193', + "dash": '\U00002010', + "dashv": '\U000022A3', + "dbkarow": '\U0000290F', + "dblac": '\U000002DD', + "dcaron": '\U0000010F', + "dcy": '\U00000434', + "dd": '\U00002146', + "ddagger": '\U00002021', + "ddarr": '\U000021CA', + "ddotseq": '\U00002A77', + "deg": '\U000000B0', + "delta": '\U000003B4', + "demptyv": '\U000029B1', + "dfisht": '\U0000297F', + "dfr": '\U0001D521', + "dharl": '\U000021C3', + "dharr": '\U000021C2', + "diam": '\U000022C4', + "diamond": '\U000022C4', + "diamondsuit": '\U00002666', + "diams": '\U00002666', + "die": '\U000000A8', + "digamma": '\U000003DD', + "disin": '\U000022F2', + "div": '\U000000F7', + "divide": '\U000000F7', + "divideontimes": '\U000022C7', + "divonx": '\U000022C7', + "djcy": '\U00000452', + "dlcorn": '\U0000231E', + "dlcrop": '\U0000230D', + "dollar": '\U00000024', + "dopf": '\U0001D555', + "dot": '\U000002D9', + "doteq": '\U00002250', + "doteqdot": '\U00002251', + "dotminus": '\U00002238', + "dotplus": '\U00002214', + "dotsquare": '\U000022A1', + "doublebarwedge": '\U00002306', + "downarrow": '\U00002193', + "downdownarrows": '\U000021CA', + "downharpoonleft": '\U000021C3', + "downharpoonright": '\U000021C2', + "drbkarow": '\U00002910', + "drcorn": '\U0000231F', + "drcrop": '\U0000230C', + "dscr": '\U0001D4B9', + "dscy": '\U00000455', + "dsol": '\U000029F6', + "dstrok": '\U00000111', + "dtdot": '\U000022F1', + "dtri": '\U000025BF', + "dtrif": '\U000025BE', + "duarr": '\U000021F5', + "duhar": '\U0000296F', + "dwangle": '\U000029A6', + "dzcy": '\U0000045F', + "dzigrarr": '\U000027FF', + "eDDot": '\U00002A77', + "eDot": '\U00002251', + "eacute": '\U000000E9', + "easter": '\U00002A6E', + "ecaron": '\U0000011B', + "ecir": '\U00002256', + "ecirc": '\U000000EA', + "ecolon": '\U00002255', + "ecy": '\U0000044D', + "edot": '\U00000117', + "ee": '\U00002147', + "efDot": '\U00002252', + "efr": '\U0001D522', + "eg": '\U00002A9A', + "egrave": '\U000000E8', + "egs": '\U00002A96', + "egsdot": '\U00002A98', + "el": '\U00002A99', + "elinters": '\U000023E7', + "ell": '\U00002113', + "els": '\U00002A95', + "elsdot": '\U00002A97', + "emacr": '\U00000113', + "empty": '\U00002205', + "emptyset": '\U00002205', + "emptyv": '\U00002205', + "emsp": '\U00002003', + "emsp13": '\U00002004', + "emsp14": '\U00002005', + "eng": '\U0000014B', + "ensp": '\U00002002', + "eogon": '\U00000119', + "eopf": '\U0001D556', + "epar": '\U000022D5', + "eparsl": '\U000029E3', + "eplus": '\U00002A71', + "epsi": '\U000003B5', + "epsilon": '\U000003B5', + "epsiv": '\U000003F5', + "eqcirc": '\U00002256', + "eqcolon": '\U00002255', + "eqsim": '\U00002242', + "eqslantgtr": '\U00002A96', + "eqslantless": '\U00002A95', + "equals": '\U0000003D', + "equest": '\U0000225F', + "equiv": '\U00002261', + "equivDD": '\U00002A78', + "eqvparsl": '\U000029E5', + "erDot": '\U00002253', + "erarr": '\U00002971', + "escr": '\U0000212F', + "esdot": '\U00002250', + "esim": '\U00002242', + "eta": '\U000003B7', + "eth": '\U000000F0', + "euml": '\U000000EB', + "euro": '\U000020AC', + "excl": '\U00000021', + "exist": '\U00002203', + "expectation": '\U00002130', + "exponentiale": '\U00002147', + "fallingdotseq": '\U00002252', + "fcy": '\U00000444', + "female": '\U00002640', + "ffilig": '\U0000FB03', + "fflig": '\U0000FB00', + "ffllig": '\U0000FB04', + "ffr": '\U0001D523', + "filig": '\U0000FB01', + "flat": '\U0000266D', + "fllig": '\U0000FB02', + "fltns": '\U000025B1', + "fnof": '\U00000192', + "fopf": '\U0001D557', + "forall": '\U00002200', + "fork": '\U000022D4', + "forkv": '\U00002AD9', + "fpartint": '\U00002A0D', + "frac12": '\U000000BD', + "frac13": '\U00002153', + "frac14": '\U000000BC', + "frac15": '\U00002155', + "frac16": '\U00002159', + "frac18": '\U0000215B', + "frac23": '\U00002154', + "frac25": '\U00002156', + "frac34": '\U000000BE', + "frac35": '\U00002157', + "frac38": '\U0000215C', + "frac45": '\U00002158', + "frac56": '\U0000215A', + "frac58": '\U0000215D', + "frac78": '\U0000215E', + "frasl": '\U00002044', + "frown": '\U00002322', + "fscr": '\U0001D4BB', + "gE": '\U00002267', + "gEl": '\U00002A8C', + "gacute": '\U000001F5', + "gamma": '\U000003B3', + "gammad": '\U000003DD', + "gap": '\U00002A86', + "gbreve": '\U0000011F', + "gcirc": '\U0000011D', + "gcy": '\U00000433', + "gdot": '\U00000121', + "ge": '\U00002265', + "gel": '\U000022DB', + "geq": '\U00002265', + "geqq": '\U00002267', + "geqslant": '\U00002A7E', + "ges": '\U00002A7E', + "gescc": '\U00002AA9', + "gesdot": '\U00002A80', + "gesdoto": '\U00002A82', + "gesdotol": '\U00002A84', + "gesles": '\U00002A94', + "gfr": '\U0001D524', + "gg": '\U0000226B', + "ggg": '\U000022D9', + "gimel": '\U00002137', + "gjcy": '\U00000453', + "gl": '\U00002277', + "glE": '\U00002A92', + "gla": '\U00002AA5', + "glj": '\U00002AA4', + "gnE": '\U00002269', + "gnap": '\U00002A8A', + "gnapprox": '\U00002A8A', + "gne": '\U00002A88', + "gneq": '\U00002A88', + "gneqq": '\U00002269', + "gnsim": '\U000022E7', + "gopf": '\U0001D558', + "grave": '\U00000060', + "gscr": '\U0000210A', + "gsim": '\U00002273', + "gsime": '\U00002A8E', + "gsiml": '\U00002A90', + "gt": '\U0000003E', + "gtcc": '\U00002AA7', + "gtcir": '\U00002A7A', + "gtdot": '\U000022D7', + "gtlPar": '\U00002995', + "gtquest": '\U00002A7C', + "gtrapprox": '\U00002A86', + "gtrarr": '\U00002978', + "gtrdot": '\U000022D7', + "gtreqless": '\U000022DB', + "gtreqqless": '\U00002A8C', + "gtrless": '\U00002277', + "gtrsim": '\U00002273', + "hArr": '\U000021D4', + "hairsp": '\U0000200A', + "half": '\U000000BD', + "hamilt": '\U0000210B', + "hardcy": '\U0000044A', + "harr": '\U00002194', + "harrcir": '\U00002948', + "harrw": '\U000021AD', + "hbar": '\U0000210F', + "hcirc": '\U00000125', + "hearts": '\U00002665', + "heartsuit": '\U00002665', + "hellip": '\U00002026', + "hercon": '\U000022B9', + "hfr": '\U0001D525', + "hksearow": '\U00002925', + "hkswarow": '\U00002926', + "hoarr": '\U000021FF', + "homtht": '\U0000223B', + "hookleftarrow": '\U000021A9', + "hookrightarrow": '\U000021AA', + "hopf": '\U0001D559', + "horbar": '\U00002015', + "hscr": '\U0001D4BD', + "hslash": '\U0000210F', + "hstrok": '\U00000127', + "hybull": '\U00002043', + "hyphen": '\U00002010', + "iacute": '\U000000ED', + "ic": '\U00002063', + "icirc": '\U000000EE', + "icy": '\U00000438', + "iecy": '\U00000435', + "iexcl": '\U000000A1', + "iff": '\U000021D4', + "ifr": '\U0001D526', + "igrave": '\U000000EC', + "ii": '\U00002148', + "iiiint": '\U00002A0C', + "iiint": '\U0000222D', + "iinfin": '\U000029DC', + "iiota": '\U00002129', + "ijlig": '\U00000133', + "imacr": '\U0000012B', + "image": '\U00002111', + "imagline": '\U00002110', + "imagpart": '\U00002111', + "imath": '\U00000131', + "imof": '\U000022B7', + "imped": '\U000001B5', + "in": '\U00002208', + "incare": '\U00002105', + "infin": '\U0000221E', + "infintie": '\U000029DD', + "inodot": '\U00000131', + "int": '\U0000222B', + "intcal": '\U000022BA', + "integers": '\U00002124', + "intercal": '\U000022BA', + "intlarhk": '\U00002A17', + "intprod": '\U00002A3C', + "iocy": '\U00000451', + "iogon": '\U0000012F', + "iopf": '\U0001D55A', + "iota": '\U000003B9', + "iprod": '\U00002A3C', + "iquest": '\U000000BF', + "iscr": '\U0001D4BE', + "isin": '\U00002208', + "isinE": '\U000022F9', + "isindot": '\U000022F5', + "isins": '\U000022F4', + "isinsv": '\U000022F3', + "isinv": '\U00002208', + "it": '\U00002062', + "itilde": '\U00000129', + "iukcy": '\U00000456', + "iuml": '\U000000EF', + "jcirc": '\U00000135', + "jcy": '\U00000439', + "jfr": '\U0001D527', + "jmath": '\U00000237', + "jopf": '\U0001D55B', + "jscr": '\U0001D4BF', + "jsercy": '\U00000458', + "jukcy": '\U00000454', + "kappa": '\U000003BA', + "kappav": '\U000003F0', + "kcedil": '\U00000137', + "kcy": '\U0000043A', + "kfr": '\U0001D528', + "kgreen": '\U00000138', + "khcy": '\U00000445', + "kjcy": '\U0000045C', + "kopf": '\U0001D55C', + "kscr": '\U0001D4C0', + "lAarr": '\U000021DA', + "lArr": '\U000021D0', + "lAtail": '\U0000291B', + "lBarr": '\U0000290E', + "lE": '\U00002266', + "lEg": '\U00002A8B', + "lHar": '\U00002962', + "lacute": '\U0000013A', + "laemptyv": '\U000029B4', + "lagran": '\U00002112', + "lambda": '\U000003BB', + "lang": '\U000027E8', + "langd": '\U00002991', + "langle": '\U000027E8', + "lap": '\U00002A85', + "laquo": '\U000000AB', + "larr": '\U00002190', + "larrb": '\U000021E4', + "larrbfs": '\U0000291F', + "larrfs": '\U0000291D', + "larrhk": '\U000021A9', + "larrlp": '\U000021AB', + "larrpl": '\U00002939', + "larrsim": '\U00002973', + "larrtl": '\U000021A2', + "lat": '\U00002AAB', + "latail": '\U00002919', + "late": '\U00002AAD', + "lbarr": '\U0000290C', + "lbbrk": '\U00002772', + "lbrace": '\U0000007B', + "lbrack": '\U0000005B', + "lbrke": '\U0000298B', + "lbrksld": '\U0000298F', + "lbrkslu": '\U0000298D', + "lcaron": '\U0000013E', + "lcedil": '\U0000013C', + "lceil": '\U00002308', + "lcub": '\U0000007B', + "lcy": '\U0000043B', + "ldca": '\U00002936', + "ldquo": '\U0000201C', + "ldquor": '\U0000201E', + "ldrdhar": '\U00002967', + "ldrushar": '\U0000294B', + "ldsh": '\U000021B2', + "le": '\U00002264', + "leftarrow": '\U00002190', + "leftarrowtail": '\U000021A2', + "leftharpoondown": '\U000021BD', + "leftharpoonup": '\U000021BC', + "leftleftarrows": '\U000021C7', + "leftrightarrow": '\U00002194', + "leftrightarrows": '\U000021C6', + "leftrightharpoons": '\U000021CB', + "leftrightsquigarrow": '\U000021AD', + "leftthreetimes": '\U000022CB', + "leg": '\U000022DA', + "leq": '\U00002264', + "leqq": '\U00002266', + "leqslant": '\U00002A7D', + "les": '\U00002A7D', + "lescc": '\U00002AA8', + "lesdot": '\U00002A7F', + "lesdoto": '\U00002A81', + "lesdotor": '\U00002A83', + "lesges": '\U00002A93', + "lessapprox": '\U00002A85', + "lessdot": '\U000022D6', + "lesseqgtr": '\U000022DA', + "lesseqqgtr": '\U00002A8B', + "lessgtr": '\U00002276', + "lesssim": '\U00002272', + "lfisht": '\U0000297C', + "lfloor": '\U0000230A', + "lfr": '\U0001D529', + "lg": '\U00002276', + "lgE": '\U00002A91', + "lhard": '\U000021BD', + "lharu": '\U000021BC', + "lharul": '\U0000296A', + "lhblk": '\U00002584', + "ljcy": '\U00000459', + "ll": '\U0000226A', + "llarr": '\U000021C7', + "llcorner": '\U0000231E', + "llhard": '\U0000296B', + "lltri": '\U000025FA', + "lmidot": '\U00000140', + "lmoust": '\U000023B0', + "lmoustache": '\U000023B0', + "lnE": '\U00002268', + "lnap": '\U00002A89', + "lnapprox": '\U00002A89', + "lne": '\U00002A87', + "lneq": '\U00002A87', + "lneqq": '\U00002268', + "lnsim": '\U000022E6', + "loang": '\U000027EC', + "loarr": '\U000021FD', + "lobrk": '\U000027E6', + "longleftarrow": '\U000027F5', + "longleftrightarrow": '\U000027F7', + "longmapsto": '\U000027FC', + "longrightarrow": '\U000027F6', + "looparrowleft": '\U000021AB', + "looparrowright": '\U000021AC', + "lopar": '\U00002985', + "lopf": '\U0001D55D', + "loplus": '\U00002A2D', + "lotimes": '\U00002A34', + "lowast": '\U00002217', + "lowbar": '\U0000005F', + "loz": '\U000025CA', + "lozenge": '\U000025CA', + "lozf": '\U000029EB', + "lpar": '\U00000028', + "lparlt": '\U00002993', + "lrarr": '\U000021C6', + "lrcorner": '\U0000231F', + "lrhar": '\U000021CB', + "lrhard": '\U0000296D', + "lrm": '\U0000200E', + "lrtri": '\U000022BF', + "lsaquo": '\U00002039', + "lscr": '\U0001D4C1', + "lsh": '\U000021B0', + "lsim": '\U00002272', + "lsime": '\U00002A8D', + "lsimg": '\U00002A8F', + "lsqb": '\U0000005B', + "lsquo": '\U00002018', + "lsquor": '\U0000201A', + "lstrok": '\U00000142', + "lt": '\U0000003C', + "ltcc": '\U00002AA6', + "ltcir": '\U00002A79', + "ltdot": '\U000022D6', + "lthree": '\U000022CB', + "ltimes": '\U000022C9', + "ltlarr": '\U00002976', + "ltquest": '\U00002A7B', + "ltrPar": '\U00002996', + "ltri": '\U000025C3', + "ltrie": '\U000022B4', + "ltrif": '\U000025C2', + "lurdshar": '\U0000294A', + "luruhar": '\U00002966', + "mDDot": '\U0000223A', + "macr": '\U000000AF', + "male": '\U00002642', + "malt": '\U00002720', + "maltese": '\U00002720', + "map": '\U000021A6', + "mapsto": '\U000021A6', + "mapstodown": '\U000021A7', + "mapstoleft": '\U000021A4', + "mapstoup": '\U000021A5', + "marker": '\U000025AE', + "mcomma": '\U00002A29', + "mcy": '\U0000043C', + "mdash": '\U00002014', + "measuredangle": '\U00002221', + "mfr": '\U0001D52A', + "mho": '\U00002127', + "micro": '\U000000B5', + "mid": '\U00002223', + "midast": '\U0000002A', + "midcir": '\U00002AF0', + "middot": '\U000000B7', + "minus": '\U00002212', + "minusb": '\U0000229F', + "minusd": '\U00002238', + "minusdu": '\U00002A2A', + "mlcp": '\U00002ADB', + "mldr": '\U00002026', + "mnplus": '\U00002213', + "models": '\U000022A7', + "mopf": '\U0001D55E', + "mp": '\U00002213', + "mscr": '\U0001D4C2', + "mstpos": '\U0000223E', + "mu": '\U000003BC', + "multimap": '\U000022B8', + "mumap": '\U000022B8', + "nLeftarrow": '\U000021CD', + "nLeftrightarrow": '\U000021CE', + "nRightarrow": '\U000021CF', + "nVDash": '\U000022AF', + "nVdash": '\U000022AE', + "nabla": '\U00002207', + "nacute": '\U00000144', + "nap": '\U00002249', + "napos": '\U00000149', + "napprox": '\U00002249', + "natur": '\U0000266E', + "natural": '\U0000266E', + "naturals": '\U00002115', + "nbsp": '\U000000A0', + "ncap": '\U00002A43', + "ncaron": '\U00000148', + "ncedil": '\U00000146', + "ncong": '\U00002247', + "ncup": '\U00002A42', + "ncy": '\U0000043D', + "ndash": '\U00002013', + "ne": '\U00002260', + "neArr": '\U000021D7', + "nearhk": '\U00002924', + "nearr": '\U00002197', + "nearrow": '\U00002197', + "nequiv": '\U00002262', + "nesear": '\U00002928', + "nexist": '\U00002204', + "nexists": '\U00002204', + "nfr": '\U0001D52B', + "nge": '\U00002271', + "ngeq": '\U00002271', + "ngsim": '\U00002275', + "ngt": '\U0000226F', + "ngtr": '\U0000226F', + "nhArr": '\U000021CE', + "nharr": '\U000021AE', + "nhpar": '\U00002AF2', + "ni": '\U0000220B', + "nis": '\U000022FC', + "nisd": '\U000022FA', + "niv": '\U0000220B', + "njcy": '\U0000045A', + "nlArr": '\U000021CD', + "nlarr": '\U0000219A', + "nldr": '\U00002025', + "nle": '\U00002270', + "nleftarrow": '\U0000219A', + "nleftrightarrow": '\U000021AE', + "nleq": '\U00002270', + "nless": '\U0000226E', + "nlsim": '\U00002274', + "nlt": '\U0000226E', + "nltri": '\U000022EA', + "nltrie": '\U000022EC', + "nmid": '\U00002224', + "nopf": '\U0001D55F', + "not": '\U000000AC', + "notin": '\U00002209', + "notinva": '\U00002209', + "notinvb": '\U000022F7', + "notinvc": '\U000022F6', + "notni": '\U0000220C', + "notniva": '\U0000220C', + "notnivb": '\U000022FE', + "notnivc": '\U000022FD', + "npar": '\U00002226', + "nparallel": '\U00002226', + "npolint": '\U00002A14', + "npr": '\U00002280', + "nprcue": '\U000022E0', + "nprec": '\U00002280', + "nrArr": '\U000021CF', + "nrarr": '\U0000219B', + "nrightarrow": '\U0000219B', + "nrtri": '\U000022EB', + "nrtrie": '\U000022ED', + "nsc": '\U00002281', + "nsccue": '\U000022E1', + "nscr": '\U0001D4C3', + "nshortmid": '\U00002224', + "nshortparallel": '\U00002226', + "nsim": '\U00002241', + "nsime": '\U00002244', + "nsimeq": '\U00002244', + "nsmid": '\U00002224', + "nspar": '\U00002226', + "nsqsube": '\U000022E2', + "nsqsupe": '\U000022E3', + "nsub": '\U00002284', + "nsube": '\U00002288', + "nsubseteq": '\U00002288', + "nsucc": '\U00002281', + "nsup": '\U00002285', + "nsupe": '\U00002289', + "nsupseteq": '\U00002289', + "ntgl": '\U00002279', + "ntilde": '\U000000F1', + "ntlg": '\U00002278', + "ntriangleleft": '\U000022EA', + "ntrianglelefteq": '\U000022EC', + "ntriangleright": '\U000022EB', + "ntrianglerighteq": '\U000022ED', + "nu": '\U000003BD', + "num": '\U00000023', + "numero": '\U00002116', + "numsp": '\U00002007', + "nvDash": '\U000022AD', + "nvHarr": '\U00002904', + "nvdash": '\U000022AC', + "nvinfin": '\U000029DE', + "nvlArr": '\U00002902', + "nvrArr": '\U00002903', + "nwArr": '\U000021D6', + "nwarhk": '\U00002923', + "nwarr": '\U00002196', + "nwarrow": '\U00002196', + "nwnear": '\U00002927', + "oS": '\U000024C8', + "oacute": '\U000000F3', + "oast": '\U0000229B', + "ocir": '\U0000229A', + "ocirc": '\U000000F4', + "ocy": '\U0000043E', + "odash": '\U0000229D', + "odblac": '\U00000151', + "odiv": '\U00002A38', + "odot": '\U00002299', + "odsold": '\U000029BC', + "oelig": '\U00000153', + "ofcir": '\U000029BF', + "ofr": '\U0001D52C', + "ogon": '\U000002DB', + "ograve": '\U000000F2', + "ogt": '\U000029C1', + "ohbar": '\U000029B5', + "ohm": '\U000003A9', + "oint": '\U0000222E', + "olarr": '\U000021BA', + "olcir": '\U000029BE', + "olcross": '\U000029BB', + "oline": '\U0000203E', + "olt": '\U000029C0', + "omacr": '\U0000014D', + "omega": '\U000003C9', + "omicron": '\U000003BF', + "omid": '\U000029B6', + "ominus": '\U00002296', + "oopf": '\U0001D560', + "opar": '\U000029B7', + "operp": '\U000029B9', + "oplus": '\U00002295', + "or": '\U00002228', + "orarr": '\U000021BB', + "ord": '\U00002A5D', + "order": '\U00002134', + "orderof": '\U00002134', + "ordf": '\U000000AA', + "ordm": '\U000000BA', + "origof": '\U000022B6', + "oror": '\U00002A56', + "orslope": '\U00002A57', + "orv": '\U00002A5B', + "oscr": '\U00002134', + "oslash": '\U000000F8', + "osol": '\U00002298', + "otilde": '\U000000F5', + "otimes": '\U00002297', + "otimesas": '\U00002A36', + "ouml": '\U000000F6', + "ovbar": '\U0000233D', + "par": '\U00002225', + "para": '\U000000B6', + "parallel": '\U00002225', + "parsim": '\U00002AF3', + "parsl": '\U00002AFD', + "part": '\U00002202', + "pcy": '\U0000043F', + "percnt": '\U00000025', + "period": '\U0000002E', + "permil": '\U00002030', + "perp": '\U000022A5', + "pertenk": '\U00002031', + "pfr": '\U0001D52D', + "phi": '\U000003C6', + "phiv": '\U000003D5', + "phmmat": '\U00002133', + "phone": '\U0000260E', + "pi": '\U000003C0', + "pitchfork": '\U000022D4', + "piv": '\U000003D6', + "planck": '\U0000210F', + "planckh": '\U0000210E', + "plankv": '\U0000210F', + "plus": '\U0000002B', + "plusacir": '\U00002A23', + "plusb": '\U0000229E', + "pluscir": '\U00002A22', + "plusdo": '\U00002214', + "plusdu": '\U00002A25', + "pluse": '\U00002A72', + "plusmn": '\U000000B1', + "plussim": '\U00002A26', + "plustwo": '\U00002A27', + "pm": '\U000000B1', + "pointint": '\U00002A15', + "popf": '\U0001D561', + "pound": '\U000000A3', + "pr": '\U0000227A', + "prE": '\U00002AB3', + "prap": '\U00002AB7', + "prcue": '\U0000227C', + "pre": '\U00002AAF', + "prec": '\U0000227A', + "precapprox": '\U00002AB7', + "preccurlyeq": '\U0000227C', + "preceq": '\U00002AAF', + "precnapprox": '\U00002AB9', + "precneqq": '\U00002AB5', + "precnsim": '\U000022E8', + "precsim": '\U0000227E', + "prime": '\U00002032', + "primes": '\U00002119', + "prnE": '\U00002AB5', + "prnap": '\U00002AB9', + "prnsim": '\U000022E8', + "prod": '\U0000220F', + "profalar": '\U0000232E', + "profline": '\U00002312', + "profsurf": '\U00002313', + "prop": '\U0000221D', + "propto": '\U0000221D', + "prsim": '\U0000227E', + "prurel": '\U000022B0', + "pscr": '\U0001D4C5', + "psi": '\U000003C8', + "puncsp": '\U00002008', + "qfr": '\U0001D52E', + "qint": '\U00002A0C', + "qopf": '\U0001D562', + "qprime": '\U00002057', + "qscr": '\U0001D4C6', + "quaternions": '\U0000210D', + "quatint": '\U00002A16', + "quest": '\U0000003F', + "questeq": '\U0000225F', + "quot": '\U00000022', + "rAarr": '\U000021DB', + "rArr": '\U000021D2', + "rAtail": '\U0000291C', + "rBarr": '\U0000290F', + "rHar": '\U00002964', + "racute": '\U00000155', + "radic": '\U0000221A', + "raemptyv": '\U000029B3', + "rang": '\U000027E9', + "rangd": '\U00002992', + "range": '\U000029A5', + "rangle": '\U000027E9', + "raquo": '\U000000BB', + "rarr": '\U00002192', + "rarrap": '\U00002975', + "rarrb": '\U000021E5', + "rarrbfs": '\U00002920', + "rarrc": '\U00002933', + "rarrfs": '\U0000291E', + "rarrhk": '\U000021AA', + "rarrlp": '\U000021AC', + "rarrpl": '\U00002945', + "rarrsim": '\U00002974', + "rarrtl": '\U000021A3', + "rarrw": '\U0000219D', + "ratail": '\U0000291A', + "ratio": '\U00002236', + "rationals": '\U0000211A', + "rbarr": '\U0000290D', + "rbbrk": '\U00002773', + "rbrace": '\U0000007D', + "rbrack": '\U0000005D', + "rbrke": '\U0000298C', + "rbrksld": '\U0000298E', + "rbrkslu": '\U00002990', + "rcaron": '\U00000159', + "rcedil": '\U00000157', + "rceil": '\U00002309', + "rcub": '\U0000007D', + "rcy": '\U00000440', + "rdca": '\U00002937', + "rdldhar": '\U00002969', + "rdquo": '\U0000201D', + "rdquor": '\U0000201D', + "rdsh": '\U000021B3', + "real": '\U0000211C', + "realine": '\U0000211B', + "realpart": '\U0000211C', + "reals": '\U0000211D', + "rect": '\U000025AD', + "reg": '\U000000AE', + "rfisht": '\U0000297D', + "rfloor": '\U0000230B', + "rfr": '\U0001D52F', + "rhard": '\U000021C1', + "rharu": '\U000021C0', + "rharul": '\U0000296C', + "rho": '\U000003C1', + "rhov": '\U000003F1', + "rightarrow": '\U00002192', + "rightarrowtail": '\U000021A3', + "rightharpoondown": '\U000021C1', + "rightharpoonup": '\U000021C0', + "rightleftarrows": '\U000021C4', + "rightleftharpoons": '\U000021CC', + "rightrightarrows": '\U000021C9', + "rightsquigarrow": '\U0000219D', + "rightthreetimes": '\U000022CC', + "ring": '\U000002DA', + "risingdotseq": '\U00002253', + "rlarr": '\U000021C4', + "rlhar": '\U000021CC', + "rlm": '\U0000200F', + "rmoust": '\U000023B1', + "rmoustache": '\U000023B1', + "rnmid": '\U00002AEE', + "roang": '\U000027ED', + "roarr": '\U000021FE', + "robrk": '\U000027E7', + "ropar": '\U00002986', + "ropf": '\U0001D563', + "roplus": '\U00002A2E', + "rotimes": '\U00002A35', + "rpar": '\U00000029', + "rpargt": '\U00002994', + "rppolint": '\U00002A12', + "rrarr": '\U000021C9', + "rsaquo": '\U0000203A', + "rscr": '\U0001D4C7', + "rsh": '\U000021B1', + "rsqb": '\U0000005D', + "rsquo": '\U00002019', + "rsquor": '\U00002019', + "rthree": '\U000022CC', + "rtimes": '\U000022CA', + "rtri": '\U000025B9', + "rtrie": '\U000022B5', + "rtrif": '\U000025B8', + "rtriltri": '\U000029CE', + "ruluhar": '\U00002968', + "rx": '\U0000211E', + "sacute": '\U0000015B', + "sbquo": '\U0000201A', + "sc": '\U0000227B', + "scE": '\U00002AB4', + "scap": '\U00002AB8', + "scaron": '\U00000161', + "sccue": '\U0000227D', + "sce": '\U00002AB0', + "scedil": '\U0000015F', + "scirc": '\U0000015D', + "scnE": '\U00002AB6', + "scnap": '\U00002ABA', + "scnsim": '\U000022E9', + "scpolint": '\U00002A13', + "scsim": '\U0000227F', + "scy": '\U00000441', + "sdot": '\U000022C5', + "sdotb": '\U000022A1', + "sdote": '\U00002A66', + "seArr": '\U000021D8', + "searhk": '\U00002925', + "searr": '\U00002198', + "searrow": '\U00002198', + "sect": '\U000000A7', + "semi": '\U0000003B', + "seswar": '\U00002929', + "setminus": '\U00002216', + "setmn": '\U00002216', + "sext": '\U00002736', + "sfr": '\U0001D530', + "sfrown": '\U00002322', + "sharp": '\U0000266F', + "shchcy": '\U00000449', + "shcy": '\U00000448', + "shortmid": '\U00002223', + "shortparallel": '\U00002225', + "shy": '\U000000AD', + "sigma": '\U000003C3', + "sigmaf": '\U000003C2', + "sigmav": '\U000003C2', + "sim": '\U0000223C', + "simdot": '\U00002A6A', + "sime": '\U00002243', + "simeq": '\U00002243', + "simg": '\U00002A9E', + "simgE": '\U00002AA0', + "siml": '\U00002A9D', + "simlE": '\U00002A9F', + "simne": '\U00002246', + "simplus": '\U00002A24', + "simrarr": '\U00002972', + "slarr": '\U00002190', + "smallsetminus": '\U00002216', + "smashp": '\U00002A33', + "smeparsl": '\U000029E4', + "smid": '\U00002223', + "smile": '\U00002323', + "smt": '\U00002AAA', + "smte": '\U00002AAC', + "softcy": '\U0000044C', + "sol": '\U0000002F', + "solb": '\U000029C4', + "solbar": '\U0000233F', + "sopf": '\U0001D564', + "spades": '\U00002660', + "spadesuit": '\U00002660', + "spar": '\U00002225', + "sqcap": '\U00002293', + "sqcup": '\U00002294', + "sqsub": '\U0000228F', + "sqsube": '\U00002291', + "sqsubset": '\U0000228F', + "sqsubseteq": '\U00002291', + "sqsup": '\U00002290', + "sqsupe": '\U00002292', + "sqsupset": '\U00002290', + "sqsupseteq": '\U00002292', + "squ": '\U000025A1', + "square": '\U000025A1', + "squarf": '\U000025AA', + "squf": '\U000025AA', + "srarr": '\U00002192', + "sscr": '\U0001D4C8', + "ssetmn": '\U00002216', + "ssmile": '\U00002323', + "sstarf": '\U000022C6', + "star": '\U00002606', + "starf": '\U00002605', + "straightepsilon": '\U000003F5', + "straightphi": '\U000003D5', + "strns": '\U000000AF', + "sub": '\U00002282', + "subE": '\U00002AC5', + "subdot": '\U00002ABD', + "sube": '\U00002286', + "subedot": '\U00002AC3', + "submult": '\U00002AC1', + "subnE": '\U00002ACB', + "subne": '\U0000228A', + "subplus": '\U00002ABF', + "subrarr": '\U00002979', + "subset": '\U00002282', + "subseteq": '\U00002286', + "subseteqq": '\U00002AC5', + "subsetneq": '\U0000228A', + "subsetneqq": '\U00002ACB', + "subsim": '\U00002AC7', + "subsub": '\U00002AD5', + "subsup": '\U00002AD3', + "succ": '\U0000227B', + "succapprox": '\U00002AB8', + "succcurlyeq": '\U0000227D', + "succeq": '\U00002AB0', + "succnapprox": '\U00002ABA', + "succneqq": '\U00002AB6', + "succnsim": '\U000022E9', + "succsim": '\U0000227F', + "sum": '\U00002211', + "sung": '\U0000266A', + "sup": '\U00002283', + "sup1": '\U000000B9', + "sup2": '\U000000B2', + "sup3": '\U000000B3', + "supE": '\U00002AC6', + "supdot": '\U00002ABE', + "supdsub": '\U00002AD8', + "supe": '\U00002287', + "supedot": '\U00002AC4', + "suphsol": '\U000027C9', + "suphsub": '\U00002AD7', + "suplarr": '\U0000297B', + "supmult": '\U00002AC2', + "supnE": '\U00002ACC', + "supne": '\U0000228B', + "supplus": '\U00002AC0', + "supset": '\U00002283', + "supseteq": '\U00002287', + "supseteqq": '\U00002AC6', + "supsetneq": '\U0000228B', + "supsetneqq": '\U00002ACC', + "supsim": '\U00002AC8', + "supsub": '\U00002AD4', + "supsup": '\U00002AD6', + "swArr": '\U000021D9', + "swarhk": '\U00002926', + "swarr": '\U00002199', + "swarrow": '\U00002199', + "swnwar": '\U0000292A', + "szlig": '\U000000DF', + "target": '\U00002316', + "tau": '\U000003C4', + "tbrk": '\U000023B4', + "tcaron": '\U00000165', + "tcedil": '\U00000163', + "tcy": '\U00000442', + "tdot": '\U000020DB', + "telrec": '\U00002315', + "tfr": '\U0001D531', + "there4": '\U00002234', + "therefore": '\U00002234', + "theta": '\U000003B8', + "thetasym": '\U000003D1', + "thetav": '\U000003D1', + "thickapprox": '\U00002248', + "thicksim": '\U0000223C', + "thinsp": '\U00002009', + "thkap": '\U00002248', + "thksim": '\U0000223C', + "thorn": '\U000000FE', + "tilde": '\U000002DC', + "times": '\U000000D7', + "timesb": '\U000022A0', + "timesbar": '\U00002A31', + "timesd": '\U00002A30', + "tint": '\U0000222D', + "toea": '\U00002928', + "top": '\U000022A4', + "topbot": '\U00002336', + "topcir": '\U00002AF1', + "topf": '\U0001D565', + "topfork": '\U00002ADA', + "tosa": '\U00002929', + "tprime": '\U00002034', + "trade": '\U00002122', + "triangle": '\U000025B5', + "triangledown": '\U000025BF', + "triangleleft": '\U000025C3', + "trianglelefteq": '\U000022B4', + "triangleq": '\U0000225C', + "triangleright": '\U000025B9', + "trianglerighteq": '\U000022B5', + "tridot": '\U000025EC', + "trie": '\U0000225C', + "triminus": '\U00002A3A', + "triplus": '\U00002A39', + "trisb": '\U000029CD', + "tritime": '\U00002A3B', + "trpezium": '\U000023E2', + "tscr": '\U0001D4C9', + "tscy": '\U00000446', + "tshcy": '\U0000045B', + "tstrok": '\U00000167', + "twixt": '\U0000226C', + "twoheadleftarrow": '\U0000219E', + "twoheadrightarrow": '\U000021A0', + "uArr": '\U000021D1', + "uHar": '\U00002963', + "uacute": '\U000000FA', + "uarr": '\U00002191', + "ubrcy": '\U0000045E', + "ubreve": '\U0000016D', + "ucirc": '\U000000FB', + "ucy": '\U00000443', + "udarr": '\U000021C5', + "udblac": '\U00000171', + "udhar": '\U0000296E', + "ufisht": '\U0000297E', + "ufr": '\U0001D532', + "ugrave": '\U000000F9', + "uharl": '\U000021BF', + "uharr": '\U000021BE', + "uhblk": '\U00002580', + "ulcorn": '\U0000231C', + "ulcorner": '\U0000231C', + "ulcrop": '\U0000230F', + "ultri": '\U000025F8', + "umacr": '\U0000016B', + "uml": '\U000000A8', + "uogon": '\U00000173', + "uopf": '\U0001D566', + "uparrow": '\U00002191', + "updownarrow": '\U00002195', + "upharpoonleft": '\U000021BF', + "upharpoonright": '\U000021BE', + "uplus": '\U0000228E', + "upsi": '\U000003C5', + "upsih": '\U000003D2', + "upsilon": '\U000003C5', + "upuparrows": '\U000021C8', + "urcorn": '\U0000231D', + "urcorner": '\U0000231D', + "urcrop": '\U0000230E', + "uring": '\U0000016F', + "urtri": '\U000025F9', + "uscr": '\U0001D4CA', + "utdot": '\U000022F0', + "utilde": '\U00000169', + "utri": '\U000025B5', + "utrif": '\U000025B4', + "uuarr": '\U000021C8', + "uuml": '\U000000FC', + "uwangle": '\U000029A7', + "vArr": '\U000021D5', + "vBar": '\U00002AE8', + "vBarv": '\U00002AE9', + "vDash": '\U000022A8', + "vangrt": '\U0000299C', + "varepsilon": '\U000003F5', + "varkappa": '\U000003F0', + "varnothing": '\U00002205', + "varphi": '\U000003D5', + "varpi": '\U000003D6', + "varpropto": '\U0000221D', + "varr": '\U00002195', + "varrho": '\U000003F1', + "varsigma": '\U000003C2', + "vartheta": '\U000003D1', + "vartriangleleft": '\U000022B2', + "vartriangleright": '\U000022B3', + "vcy": '\U00000432', + "vdash": '\U000022A2', + "vee": '\U00002228', + "veebar": '\U000022BB', + "veeeq": '\U0000225A', + "vellip": '\U000022EE', + "verbar": '\U0000007C', + "vert": '\U0000007C', + "vfr": '\U0001D533', + "vltri": '\U000022B2', + "vopf": '\U0001D567', + "vprop": '\U0000221D', + "vrtri": '\U000022B3', + "vscr": '\U0001D4CB', + "vzigzag": '\U0000299A', + "wcirc": '\U00000175', + "wedbar": '\U00002A5F', + "wedge": '\U00002227', + "wedgeq": '\U00002259', + "weierp": '\U00002118', + "wfr": '\U0001D534', + "wopf": '\U0001D568', + "wp": '\U00002118', + "wr": '\U00002240', + "wreath": '\U00002240', + "wscr": '\U0001D4CC', + "xcap": '\U000022C2', + "xcirc": '\U000025EF', + "xcup": '\U000022C3', + "xdtri": '\U000025BD', + "xfr": '\U0001D535', + "xhArr": '\U000027FA', + "xharr": '\U000027F7', + "xi": '\U000003BE', + "xlArr": '\U000027F8', + "xlarr": '\U000027F5', + "xmap": '\U000027FC', + "xnis": '\U000022FB', + "xodot": '\U00002A00', + "xopf": '\U0001D569', + "xoplus": '\U00002A01', + "xotime": '\U00002A02', + "xrArr": '\U000027F9', + "xrarr": '\U000027F6', + "xscr": '\U0001D4CD', + "xsqcup": '\U00002A06', + "xuplus": '\U00002A04', + "xutri": '\U000025B3', + "xvee": '\U000022C1', + "xwedge": '\U000022C0', + "yacute": '\U000000FD', + "yacy": '\U0000044F', + "ycirc": '\U00000177', + "ycy": '\U0000044B', + "yen": '\U000000A5', + "yfr": '\U0001D536', + "yicy": '\U00000457', + "yopf": '\U0001D56A', + "yscr": '\U0001D4CE', + "yucy": '\U0000044E', + "yuml": '\U000000FF', + "zacute": '\U0000017A', + "zcaron": '\U0000017E', + "zcy": '\U00000437', + "zdot": '\U0000017C', + "zeetrf": '\U00002128', + "zeta": '\U000003B6', + "zfr": '\U0001D537', + "zhcy": '\U00000436', + "zigrarr": '\U000021DD', + "zopf": '\U0001D56B', + "zscr": '\U0001D4CF', + "zwj": '\U0000200D', + "zwnj": '\U0000200C', +} diff --git a/vendor/github.com/k3a/html2text/html2text.go b/vendor/github.com/k3a/html2text/html2text.go new file mode 100644 index 000000000..f79fbe395 --- /dev/null +++ b/vendor/github.com/k3a/html2text/html2text.go @@ -0,0 +1,333 @@ +package html2text + +import ( + "bytes" + "regexp" + "strconv" + "strings" +) + +// Line break constants +// Deprecated: Please use HTML2TextWithOptions(text, WithUnixLineBreak()) +const ( + WIN_LBR = "\r\n" + UNIX_LBR = "\n" +) + +var legacyLBR = WIN_LBR +var badTagnamesRE = regexp.MustCompile(`^(head|script|style|a)($|\s+)`) +var linkTagRE = regexp.MustCompile(`^(?i:a)(?:$|\s).*(?i:href)\s*=\s*('([^']*?)'|"([^"]*?)"|([^\s"'` + "`" + `=<>]+))`) +var badLinkHrefRE = regexp.MustCompile(`javascript:`) +var headersRE = regexp.MustCompile(`^(\/)?h[1-6]`) +var numericEntityRE = regexp.MustCompile(`(?i)^#(x?[a-f0-9]+)$`) + +type options struct { + lbr string + linksInnerText bool + listPrefix string +} + +func newOptions() *options { + // apply defaults + return &options{ + lbr: WIN_LBR, + } +} + +// Option is a functional option +type Option func(*options) + +// WithUnixLineBreaks instructs the converter to use unix line breaks ("\n" instead of "\r\n" default) +func WithUnixLineBreaks() Option { + return func(o *options) { + o.lbr = UNIX_LBR + } +} + +// WithLinksInnerText instructs the converter to retain link tag inner text and append href URLs in angle brackets after the text +// Example: click news +func WithLinksInnerText() Option { + return func(o *options) { + o.linksInnerText = true + } +} + +// WithListSupportPrefix formats