From 081f4a51237034cb7e4a9f40fd6c503686ac87ff Mon Sep 17 00:00:00 2001 From: Ahmad Karlam Date: Tue, 29 Jun 2021 10:24:13 +0700 Subject: [PATCH] [MM-11143] Strip markdown formatting characters from push notifications (#17775) * WIP: trim markdown for push notification * fix: golangci * fix: table regex * fix: regex code block * doc: add license * WIP: custom renderer with goldmark * WIP: update goldmark version to 1.38 * fix: use goldmark as parser * fix: remove table extension * fix: change buf to `strings.Builder` * fix: return original string, log warning if error * refactor: change `WriteString` to `WriteByte` * refactor: change if condition * refactor: use assertion * refactor: move to inline * fix: remove handle multiline Already handled by mobile * refactor: wrap same function * refactor: move strip markdown to `sendPushNotificationSync` * refactor: renaming variable aren't used * fix: move log to func `sendPushNotificationSync` * docs: add comment to `StripMarkdown` * fix: move assign message to else * appErr to err rename Co-authored-by: Agniva De Sarker Co-authored-by: Mattermod --- app/notification_push.go | 13 +- go.mod | 6 +- go.sum | 17 +- utils/markdown.go | 142 ++ utils/markdown_test.go | 282 +++ vendor/github.com/yuin/goldmark/.gitignore | 19 + vendor/github.com/yuin/goldmark/LICENSE | 21 + vendor/github.com/yuin/goldmark/Makefile | 16 + vendor/github.com/yuin/goldmark/README.md | 490 ++++ vendor/github.com/yuin/goldmark/ast/ast.go | 508 ++++ vendor/github.com/yuin/goldmark/ast/block.go | 495 ++++ vendor/github.com/yuin/goldmark/ast/inline.go | 548 +++++ .../goldmark/extension/ast/definition_list.go | 83 + .../yuin/goldmark/extension/ast/footnote.go | 132 + .../goldmark/extension/ast/strikethrough.go | 29 + .../yuin/goldmark/extension/ast/table.go | 157 ++ .../yuin/goldmark/extension/ast/tasklist.go | 35 + .../goldmark/extension/definition_list.go | 270 +++ .../yuin/goldmark/extension/footnote.go | 670 ++++++ .../github.com/yuin/goldmark/extension/gfm.go | 18 + .../yuin/goldmark/extension/linkify.go | 307 +++ .../yuin/goldmark/extension/strikethrough.go | 116 + .../yuin/goldmark/extension/table.go | 552 +++++ .../yuin/goldmark/extension/tasklist.go | 115 + .../yuin/goldmark/extension/typographer.go | 323 +++ vendor/github.com/yuin/goldmark/go.mod | 3 + vendor/github.com/yuin/goldmark/go.sum | 0 vendor/github.com/yuin/goldmark/markdown.go | 140 ++ .../yuin/goldmark/parser/attribute.go | 328 +++ .../yuin/goldmark/parser/atx_heading.go | 243 ++ .../yuin/goldmark/parser/auto_link.go | 42 + .../yuin/goldmark/parser/blockquote.go | 69 + .../yuin/goldmark/parser/code_block.go | 96 + .../yuin/goldmark/parser/code_span.go | 83 + .../yuin/goldmark/parser/delimiter.go | 241 ++ .../yuin/goldmark/parser/emphasis.go | 50 + .../yuin/goldmark/parser/fcode_block.go | 115 + .../yuin/goldmark/parser/html_block.go | 228 ++ .../github.com/yuin/goldmark/parser/link.go | 379 +++ .../yuin/goldmark/parser/link_ref.go | 163 ++ .../github.com/yuin/goldmark/parser/list.go | 253 ++ .../yuin/goldmark/parser/list_item.go | 87 + .../yuin/goldmark/parser/paragraph.go | 71 + .../github.com/yuin/goldmark/parser/parser.go | 1229 ++++++++++ .../yuin/goldmark/parser/raw_html.go | 103 + .../yuin/goldmark/parser/setext_headings.go | 126 + .../yuin/goldmark/parser/thematic_break.go | 75 + .../yuin/goldmark/renderer/html/html.go | 805 +++++++ .../yuin/goldmark/renderer/renderer.go | 174 ++ .../github.com/yuin/goldmark/text/reader.go | 543 +++++ .../github.com/yuin/goldmark/text/segment.go | 209 ++ .../yuin/goldmark/util/html5entities.go | 2142 +++++++++++++++++ .../goldmark/util/unicode_case_folding.go | 1491 ++++++++++++ vendor/github.com/yuin/goldmark/util/util.go | 992 ++++++++ .../yuin/goldmark/util/util_safe.go | 13 + .../yuin/goldmark/util/util_unsafe.go | 23 + vendor/modules.txt | 12 +- 57 files changed, 15870 insertions(+), 22 deletions(-) create mode 100644 utils/markdown.go create mode 100644 utils/markdown_test.go create mode 100644 vendor/github.com/yuin/goldmark/.gitignore create mode 100644 vendor/github.com/yuin/goldmark/LICENSE create mode 100644 vendor/github.com/yuin/goldmark/Makefile create mode 100644 vendor/github.com/yuin/goldmark/README.md create mode 100644 vendor/github.com/yuin/goldmark/ast/ast.go create mode 100644 vendor/github.com/yuin/goldmark/ast/block.go create mode 100644 vendor/github.com/yuin/goldmark/ast/inline.go create mode 100644 vendor/github.com/yuin/goldmark/extension/ast/definition_list.go create mode 100644 vendor/github.com/yuin/goldmark/extension/ast/footnote.go create mode 100644 vendor/github.com/yuin/goldmark/extension/ast/strikethrough.go create mode 100644 vendor/github.com/yuin/goldmark/extension/ast/table.go create mode 100644 vendor/github.com/yuin/goldmark/extension/ast/tasklist.go create mode 100644 vendor/github.com/yuin/goldmark/extension/definition_list.go create mode 100644 vendor/github.com/yuin/goldmark/extension/footnote.go create mode 100644 vendor/github.com/yuin/goldmark/extension/gfm.go create mode 100644 vendor/github.com/yuin/goldmark/extension/linkify.go create mode 100644 vendor/github.com/yuin/goldmark/extension/strikethrough.go create mode 100644 vendor/github.com/yuin/goldmark/extension/table.go create mode 100644 vendor/github.com/yuin/goldmark/extension/tasklist.go create mode 100644 vendor/github.com/yuin/goldmark/extension/typographer.go create mode 100644 vendor/github.com/yuin/goldmark/go.mod create mode 100644 vendor/github.com/yuin/goldmark/go.sum create mode 100644 vendor/github.com/yuin/goldmark/markdown.go create mode 100644 vendor/github.com/yuin/goldmark/parser/attribute.go create mode 100644 vendor/github.com/yuin/goldmark/parser/atx_heading.go create mode 100644 vendor/github.com/yuin/goldmark/parser/auto_link.go create mode 100644 vendor/github.com/yuin/goldmark/parser/blockquote.go create mode 100644 vendor/github.com/yuin/goldmark/parser/code_block.go create mode 100644 vendor/github.com/yuin/goldmark/parser/code_span.go create mode 100644 vendor/github.com/yuin/goldmark/parser/delimiter.go create mode 100644 vendor/github.com/yuin/goldmark/parser/emphasis.go create mode 100644 vendor/github.com/yuin/goldmark/parser/fcode_block.go create mode 100644 vendor/github.com/yuin/goldmark/parser/html_block.go create mode 100644 vendor/github.com/yuin/goldmark/parser/link.go create mode 100644 vendor/github.com/yuin/goldmark/parser/link_ref.go create mode 100644 vendor/github.com/yuin/goldmark/parser/list.go create mode 100644 vendor/github.com/yuin/goldmark/parser/list_item.go create mode 100644 vendor/github.com/yuin/goldmark/parser/paragraph.go create mode 100644 vendor/github.com/yuin/goldmark/parser/parser.go create mode 100644 vendor/github.com/yuin/goldmark/parser/raw_html.go create mode 100644 vendor/github.com/yuin/goldmark/parser/setext_headings.go create mode 100644 vendor/github.com/yuin/goldmark/parser/thematic_break.go create mode 100644 vendor/github.com/yuin/goldmark/renderer/html/html.go create mode 100644 vendor/github.com/yuin/goldmark/renderer/renderer.go create mode 100644 vendor/github.com/yuin/goldmark/text/reader.go create mode 100644 vendor/github.com/yuin/goldmark/text/segment.go create mode 100644 vendor/github.com/yuin/goldmark/util/html5entities.go create mode 100644 vendor/github.com/yuin/goldmark/util/unicode_case_folding.go create mode 100644 vendor/github.com/yuin/goldmark/util/util.go create mode 100644 vendor/github.com/yuin/goldmark/util/util_safe.go create mode 100644 vendor/github.com/yuin/goldmark/util/util_unsafe.go diff --git a/app/notification_push.go b/app/notification_push.go index d7fbc739fa..b69b52aeac 100644 --- a/app/notification_push.go +++ b/app/notification_push.go @@ -16,6 +16,7 @@ import ( "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/shared/mlog" + "github.com/mattermost/mattermost-server/v5/utils" ) type notificationType string @@ -55,7 +56,13 @@ type PushNotification struct { func (a *App) sendPushNotificationSync(post *model.Post, user *model.User, channel *model.Channel, channelName string, senderName string, explicitMention bool, channelWideMention bool, replyToThreadType string) *model.AppError { cfg := a.Config() - msg, err := a.BuildPushNotificationMessage( + message, err := utils.StripMarkdown(post.Message) + if err != nil { + mlog.Warn("Failed parse to markdown", mlog.String("post_id", post.Id), mlog.Err(err)) + } else { + post.Message = message + } + msg, appErr := a.BuildPushNotificationMessage( *cfg.EmailSettings.PushNotificationContents, post, user, @@ -66,8 +73,8 @@ func (a *App) sendPushNotificationSync(post *model.Post, user *model.User, chann channelWideMention, replyToThreadType, ) - if err != nil { - return err + if appErr != nil { + return appErr } return a.sendPushNotificationToAllSessions(msg, user.Id, "") diff --git a/go.mod b/go.mod index d2eb63b5fc..1c68d751b9 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428 github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 github.com/jmoiron/sqlx v1.3.4 - github.com/jonboulle/clockwork v0.2.2 + github.com/jonboulle/clockwork v0.2.2 // indirect github.com/json-iterator/go v1.1.11 // indirect github.com/klauspost/compress v1.12.3 // indirect github.com/klauspost/cpuid/v2 v2.0.6 // indirect @@ -95,13 +95,12 @@ require ( github.com/pierrec/lz4/v4 v4.1.7 // indirect github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.10.0 - github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.25.0 // indirect github.com/reflog/dateconstraints v0.2.1 github.com/rs/cors v1.7.0 github.com/rs/xid v1.3.0 // indirect github.com/rudderlabs/analytics-go v3.3.1+incompatible - github.com/russellhaering/goxmldsig v1.1.0 + github.com/russellhaering/goxmldsig v1.1.0 // indirect github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect github.com/sirupsen/logrus v1.8.1 @@ -123,6 +122,7 @@ require ( github.com/wiggin77/srslog v1.0.1 github.com/willf/bitset v1.1.11 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c + github.com/yuin/goldmark v1.3.8 go.etcd.io/bbolt v1.3.6 // indirect go.uber.org/multierr v1.7.0 // indirect go.uber.org/zap v1.17.0 diff --git a/go.sum b/go.sum index 72a2a7e807..1af0b6c1bd 100644 --- a/go.sum +++ b/go.sum @@ -290,7 +290,6 @@ github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGE github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -316,7 +315,6 @@ github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NB github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= -github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag= @@ -342,7 +340,6 @@ github.com/go-resty/resty/v2 v2.3.0/go.mod h1:UpN9CgLZNsv4e9XG50UU8xdI0F43UQ4Hmx github.com/go-resty/resty/v2 v2.6.0 h1:joIR5PNLM2EFqqESUjCMGXrWmXNHEU9CEiK813oKYS4= github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -592,7 +589,6 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -700,7 +696,6 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -708,7 +703,6 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -929,7 +923,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -1055,7 +1048,6 @@ github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.1.1 h1:nt6/Ot5LtZnJCWwEFlelOixPo0xhPFsuZlKyOL3Xfnc= github.com/tidwall/pretty v1.1.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= @@ -1124,13 +1116,14 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E= +github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -1162,7 +1155,6 @@ go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= @@ -1193,7 +1185,6 @@ golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= @@ -1226,7 +1217,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= @@ -1399,7 +1389,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1471,7 +1460,6 @@ golang.org/x/tools v0.0.0-20200818005847-188abfa75333/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1650,7 +1638,6 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg= modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8= diff --git a/utils/markdown.go b/utils/markdown.go new file mode 100644 index 0000000000..3b79589966 --- /dev/null +++ b/utils/markdown.go @@ -0,0 +1,142 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package utils + +import ( + "strings" + + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension" + astExt "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/util" +) + +// StripMarkdown remove some markdown syntax +func StripMarkdown(markdown string) (string, error) { + md := goldmark.New( + goldmark.WithExtensions(extension.Strikethrough), + goldmark.WithRenderer( + renderer.NewRenderer(renderer.WithNodeRenderers( + util.Prioritized(newNotificationRenderer(), 500), + )), + ), + ) + + var buf strings.Builder + if err := md.Convert([]byte(markdown), &buf); err != nil { + return "", err + } + + return strings.TrimSpace(buf.String()), nil +} + +type notificationRenderer struct { +} + +func newNotificationRenderer() *notificationRenderer { + return ¬ificationRenderer{} +} + +func (r *notificationRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + // block + reg.Register(ast.KindDocument, r.renderDefault) + reg.Register(ast.KindHeading, r.renderItem) + reg.Register(ast.KindBlockquote, r.renderDefault) + reg.Register(ast.KindCodeBlock, r.renderCodeBlock) + reg.Register(ast.KindFencedCodeBlock, r.renderFencedCodeBlock) + reg.Register(ast.KindHTMLBlock, r.renderDefault) + reg.Register(ast.KindList, r.renderDefault) + reg.Register(ast.KindListItem, r.renderItem) + reg.Register(ast.KindParagraph, r.renderItem) + reg.Register(ast.KindTextBlock, r.renderTextBlock) + reg.Register(ast.KindThematicBreak, r.renderDefault) + + // inlines + reg.Register(ast.KindAutoLink, r.renderDefault) + reg.Register(ast.KindCodeSpan, r.renderDefault) + reg.Register(ast.KindEmphasis, r.renderDefault) + reg.Register(ast.KindImage, r.renderDefault) + reg.Register(ast.KindLink, r.renderDefault) + reg.Register(ast.KindRawHTML, r.renderDefault) + reg.Register(ast.KindText, r.renderText) + reg.Register(ast.KindString, r.renderString) + + // strikethrough + reg.Register(astExt.KindStrikethrough, r.renderDefault) +} + +// renderDefault renderer function to renderDefault without changes +func (r *notificationRenderer) renderDefault(_ util.BufWriter, _ []byte, _ ast.Node, _ bool) (ast.WalkStatus, error) { + return ast.WalkContinue, nil +} + +func (r *notificationRenderer) renderItem(w util.BufWriter, _ []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + if node.NextSibling() != nil { + _ = w.WriteByte(' ') + } + } + return ast.WalkContinue, nil +} + +func (r *notificationRenderer) renderCodeBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.CodeBlock) + if entering { + r.writeLines(w, source, n) + } + + return ast.WalkContinue, nil +} + +func (r *notificationRenderer) renderFencedCodeBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.FencedCodeBlock) + if entering { + r.writeLines(w, source, n) + } + + return ast.WalkContinue, nil +} + +func (r *notificationRenderer) renderText(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + n := node.(*ast.Text) + segment := n.Segment + _, _ = w.Write(segment.Value(source)) + if !n.IsRaw() { + if n.HardLineBreak() || n.SoftLineBreak() { + _ = w.WriteByte('\n') + } + } + return ast.WalkContinue, nil +} + +func (r *notificationRenderer) renderTextBlock(w util.BufWriter, _ []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + if _, ok := node.NextSibling().(ast.Node); ok && node.FirstChild() != nil { + _ = w.WriteByte(' ') + } + } + return ast.WalkContinue, nil +} + +func (r *notificationRenderer) renderString(w util.BufWriter, _ []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + n := node.(*ast.String) + _, _ = w.Write(n.Value) + return ast.WalkContinue, nil +} + +func (r *notificationRenderer) writeLines(w util.BufWriter, source []byte, n ast.Node) { + for i := 0; i < n.Lines().Len(); i++ { + line := n.Lines().At(i) + value := line.Value(source) + _, _ = w.Write(value) + } +} diff --git a/utils/markdown_test.go b/utils/markdown_test.go new file mode 100644 index 0000000000..85e7212d21 --- /dev/null +++ b/utils/markdown_test.go @@ -0,0 +1,282 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package utils + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestStripMarkdown(t *testing.T) { + tests := []struct { + name string + args string + want string + }{ + { + name: "emoji: same", + args: "Hey :smile: :+1: :)", + want: "Hey :smile: :+1: :)", + }, + { + name: "at-mention: same", + args: "Hey @user and @test", + want: "Hey @user and @test", + }, + { + name: "channel-link: same", + args: "join ~channelname", + want: "join ~channelname", + }, + { + name: "codespan: single backtick", + args: "`single backtick`", + want: "single backtick", + }, + { + name: "codespan: double backtick", + args: "``double backtick``", + want: "double backtick", + }, + { + name: "codespan: triple backtick", + args: "```triple backtick```", + want: "triple backtick", + }, + { + name: "codespan: inline code", + args: "Inline `code` has ``double backtick`` and ```triple backtick``` around it.", + want: "Inline code has double backtick and triple backtick around it.", + }, + { + name: "code block: single line code block", + args: "Code block\n```\nline\n```", + want: "Code block line", + }, + { + name: "code block: multiline code block 2", + args: "Multiline\n```\nfunction(number) {\n return number + 1;\n}\n```", + want: "Multiline function(number) {\n return number + 1;\n}", + }, + { + name: "code block: language highlighting", + args: "```javascript\nvar s = \"JavaScript syntax highlighting\";\nalert(s);\n```", + want: "var s = \"JavaScript syntax highlighting\";\nalert(s);", + }, + { + name: "blockquote:", + args: "> Hey quote", + want: "Hey quote", + }, + { + name: "blockquote: multiline", + args: "> Hey quote.\n> Hello quote.", + want: "Hey quote.\nHello quote.", + }, + { + name: "heading: # H1 header", + args: "# H1 header", + want: "H1 header", + }, + { + name: "heading: heading with @user", + args: "# H1 @user", + want: "H1 @user", + }, + { + name: "heading: ## H2 header", + args: "## H2 header", + want: "H2 header", + }, + { + name: "heading: ### H3 header", + args: "### H3 header", + want: "H3 header", + }, + { + name: "heading: #### H4 header", + args: "#### H4 header", + want: "H4 header", + }, + { + name: "heading: ##### H5 header", + args: "##### H5 header", + want: "H5 header", + }, + { + name: "heading: ###### H6 header", + args: "###### H6 header", + want: "H6 header", + }, + { + name: "heading: multiline with header and paragraph", + args: "###### H6 header\nThis is next line.\nAnother line.", + want: "H6 header This is next line.\nAnother line.", + }, + { + name: "heading: multiline with header and list items", + args: "###### H6 header\n- list item 1\n- list item 2", + want: "H6 header list item 1 list item 2", + }, + { + name: "heading: multiline with header and links", + args: "###### H6 header\n[link 1](https://mattermost.com) - [link 2](https://mattermost.com)", + want: "H6 header link 1 - link 2", + }, + { + name: "list: 1. First ordered list item", + args: "1. First ordered list item", + want: "First ordered list item", + }, + { + name: "list: 2. Another item", + args: "1. 2. Another item", + want: "Another item", + }, + { + name: "list: * Unordered sub-list.", + args: "* Unordered sub-list.", + want: "Unordered sub-list.", + }, + { + name: "list: - Or minuses", + args: "- Or minuses", + want: "Or minuses", + }, + { + name: "list: + Or pluses", + args: "+ Or pluses", + want: "Or pluses", + }, + { + name: "list: multiline", + args: "1. First ordered list item\n2. Another item", + want: "First ordered list item Another item", + }, + { + name: "tablerow:)", + args: "Markdown | Less | Pretty\n" + + "--- | --- | ---\n" + + "*Still* | `renders` | **nicely**\n" + + "1 | 2 | 3\n", + want: "Markdown | Less | Pretty\n" + + "--- | --- | ---\n" + + "Still | renders | nicely\n" + + "1 | 2 | 3", + }, + { + name: "table:", + args: "| Tables | Are | Cool |\n" + + "| ------------- |:-------------:| -----:|\n" + + "| col 3 is | right-aligned | $1600 |\n" + + "| col 2 is | centered | $12 |\n" + + "| zebra stripes | are neat | $1 |\n", + want: "| Tables | Are | Cool |\n" + + "| ------------- |:-------------:| -----:|\n" + + "| col 3 is | right-aligned | $1600 |\n" + + "| col 2 is | centered | $12 |\n" + + "| zebra stripes | are neat | $1 |", + }, + { + name: "strong: Bold with **asterisks** or __underscores__.", + args: "Bold with **asterisks** or __underscores__.", + want: "Bold with asterisks or underscores.", + }, + { + name: "strong & em: Bold and italics with **asterisks and _underscores_**.", + args: "Bold and italics with **asterisks and _underscores_**.", + want: "Bold and italics with asterisks and underscores.", + }, + { + name: "em: Italics with *asterisks* or _underscores_.", + args: "Italics with *asterisks* or _underscores_.", + want: "Italics with asterisks or underscores.", + }, + { + name: "del: Strikethrough ~~strike this.~~", + args: "Strikethrough ~~strike this.~~", + want: "Strikethrough strike this.", + }, + { + name: "links: [inline-style link](http://localhost:8065)", + args: "[inline-style link](http://localhost:8065)", + want: "inline-style link", + }, + { + name: "image: ![image link](http://localhost:8065/image)", + args: "![image link](http://localhost:8065/image)", + want: "image link", + }, + { + name: "text: plain", + args: "This is plain text.", + want: "This is plain text.", + }, + { + name: "text: multiline", + args: "This is multiline text.\nHere is the next line.\n", + want: "This is multiline text.\nHere is the next line.", + }, + { + name: "text: multiline with blockquote", + args: "This is multiline text.\n> With quote", + want: "This is multiline text. With quote", + }, + { + name: "text: multiline with list items", + args: "This is multiline text.\n * List item ", + want: "This is multiline text. List item", + }, + { + name: "text: & entity", + args: "you & me", + want: "you & me", + }, + { + name: "text: < entity", + args: "1<2", + want: "1<2", + }, + { + name: "text: > entity", + args: "2>1", + want: "2>1", + }, + { + name: "text: ' entity", + args: "he's out", + want: "he's out", + }, + { + name: "text: " entity", + args: `That is "unique"`, + want: `That is "unique"`, + }, + { + name: "text: multiple entities", + args: "&<>'", + want: "&<>'", + }, + { + name: "text: multiple entities", + args: "'><&", + want: "'><&", + }, + { + name: "text: empty string", + args: "", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := StripMarkdown(tt.args) + if err != nil { + t.Fatalf("error: %v", err) + } + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/vendor/github.com/yuin/goldmark/.gitignore b/vendor/github.com/yuin/goldmark/.gitignore new file mode 100644 index 0000000000..06c135f17e --- /dev/null +++ b/vendor/github.com/yuin/goldmark/.gitignore @@ -0,0 +1,19 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test +*.pprof + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +.DS_Store +fuzz/corpus +fuzz/crashers +fuzz/suppressions +fuzz/fuzz-fuzz.zip diff --git a/vendor/github.com/yuin/goldmark/LICENSE b/vendor/github.com/yuin/goldmark/LICENSE new file mode 100644 index 0000000000..dc5b2a6906 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Yusuke Inuzuka + +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/yuin/goldmark/Makefile b/vendor/github.com/yuin/goldmark/Makefile new file mode 100644 index 0000000000..667a19a474 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/Makefile @@ -0,0 +1,16 @@ +.PHONY: test fuzz + +test: + go test -coverprofile=profile.out -coverpkg=github.com/yuin/goldmark,github.com/yuin/goldmark/ast,github.com/yuin/goldmark/extension,github.com/yuin/goldmark/extension/ast,github.com/yuin/goldmark/parser,github.com/yuin/goldmark/renderer,github.com/yuin/goldmark/renderer/html,github.com/yuin/goldmark/text,github.com/yuin/goldmark/util ./... + +cov: test + go tool cover -html=profile.out + +fuzz: + which go-fuzz > /dev/null 2>&1 || (GO111MODULE=off go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build; GO111MODULE=off go get -d github.com/dvyukov/go-fuzz-corpus; true) + rm -rf ./fuzz/corpus + rm -rf ./fuzz/crashers + rm -rf ./fuzz/suppressions + rm -f ./fuzz/fuzz-fuzz.zip + cd ./fuzz && go-fuzz-build + cd ./fuzz && go-fuzz diff --git a/vendor/github.com/yuin/goldmark/README.md b/vendor/github.com/yuin/goldmark/README.md new file mode 100644 index 0000000000..5520346acd --- /dev/null +++ b/vendor/github.com/yuin/goldmark/README.md @@ -0,0 +1,490 @@ +goldmark +========================================== + +[![https://pkg.go.dev/github.com/yuin/goldmark](https://pkg.go.dev/badge/github.com/yuin/goldmark.svg)](https://pkg.go.dev/github.com/yuin/goldmark) +[![https://github.com/yuin/goldmark/actions?query=workflow:test](https://github.com/yuin/goldmark/workflows/test/badge.svg?branch=master&event=push)](https://github.com/yuin/goldmark/actions?query=workflow:test) +[![https://coveralls.io/github/yuin/goldmark](https://coveralls.io/repos/github/yuin/goldmark/badge.svg?branch=master)](https://coveralls.io/github/yuin/goldmark) +[![https://goreportcard.com/report/github.com/yuin/goldmark](https://goreportcard.com/badge/github.com/yuin/goldmark)](https://goreportcard.com/report/github.com/yuin/goldmark) + +> A Markdown parser written in Go. Easy to extend, standards-compliant, well-structured. + +goldmark is compliant with CommonMark 0.29. + +Motivation +---------------------- +I needed a Markdown parser for Go that satisfies the following requirements: + +- Easy to extend. + - Markdown is poor in document expressions compared to other light markup languages such as reStructuredText. + - We have extensions to the Markdown syntax, e.g. PHP Markdown Extra, GitHub Flavored Markdown. +- Standards-compliant. + - Markdown has many dialects. + - GitHub-Flavored Markdown is widely used and is based upon CommonMark, effectively mooting the question of whether or not CommonMark is an ideal specification. + - CommonMark is complicated and hard to implement. +- Well-structured. + - AST-based; preserves source position of nodes. +- Written in pure Go. + +[golang-commonmark](https://gitlab.com/golang-commonmark/markdown) may be a good choice, but it seems to be a copy of [markdown-it](https://github.com/markdown-it). + +[blackfriday.v2](https://github.com/russross/blackfriday/tree/v2) is a fast and widely-used implementation, but is not CommonMark-compliant and cannot be extended from outside of the package, since its AST uses structs instead of interfaces. + +Furthermore, its behavior differs from other implementations in some cases, especially regarding lists: [Deep nested lists don't output correctly #329](https://github.com/russross/blackfriday/issues/329), [List block cannot have a second line #244](https://github.com/russross/blackfriday/issues/244), etc. + +This behavior sometimes causes problems. If you migrate your Markdown text from GitHub to blackfriday-based wikis, many lists will immediately be broken. + +As mentioned above, CommonMark is complicated and hard to implement, so Markdown parsers based on CommonMark are few and far between. + +Features +---------------------- + +- **Standards-compliant.** goldmark is fully compliant with the latest [CommonMark](https://commonmark.org/) specification. +- **Extensible.** Do you want to add a `@username` mention syntax to Markdown? + You can easily do so in goldmark. You can add your AST nodes, + parsers for block-level elements, parsers for inline-level elements, + transformers for paragraphs, transformers for the whole AST structure, and + renderers. +- **Performance.** goldmark's performance is on par with that of cmark, + the CommonMark reference implementation written in C. +- **Robust.** goldmark is tested with [go-fuzz](https://github.com/dvyukov/go-fuzz), a fuzz testing tool. +- **Built-in extensions.** goldmark ships with common extensions like tables, strikethrough, + task lists, and definition lists. +- **Depends only on standard libraries.** + +Installation +---------------------- +```bash +$ go get github.com/yuin/goldmark +``` + + +Usage +---------------------- +Import packages: + +```go +import ( + "bytes" + "github.com/yuin/goldmark" +) +``` + + +Convert Markdown documents with the CommonMark-compliant mode: + +```go +var buf bytes.Buffer +if err := goldmark.Convert(source, &buf); err != nil { + panic(err) +} +``` + +With options +------------------------------ + +```go +var buf bytes.Buffer +if err := goldmark.Convert(source, &buf, parser.WithContext(ctx)); err != nil { + panic(err) +} +``` + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `parser.WithContext` | A `parser.Context` | Context for the parsing phase. | + +Context options +---------------------- + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `parser.WithIDs` | A `parser.IDs` | `IDs` allows you to change logics that are related to element id(ex: Auto heading id generation). | + + +Custom parser and renderer +-------------------------- +```go +import ( + "bytes" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer/html" +) + +md := goldmark.New( + goldmark.WithExtensions(extension.GFM), + goldmark.WithParserOptions( + parser.WithAutoHeadingID(), + ), + goldmark.WithRendererOptions( + html.WithHardWraps(), + html.WithXHTML(), + ), + ) +var buf bytes.Buffer +if err := md.Convert(source, &buf); err != nil { + panic(err) +} +``` + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `goldmark.WithParser` | `parser.Parser` | This option must be passed before `goldmark.WithParserOptions` and `goldmark.WithExtensions` | +| `goldmark.WithRenderer` | `renderer.Renderer` | This option must be passed before `goldmark.WithRendererOptions` and `goldmark.WithExtensions` | +| `goldmark.WithParserOptions` | `...parser.Option` | | +| `goldmark.WithRendererOptions` | `...renderer.Option` | | +| `goldmark.WithExtensions` | `...goldmark.Extender` | | + +Parser and Renderer options +------------------------------ + +### Parser options + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `parser.WithBlockParsers` | A `util.PrioritizedSlice` whose elements are `parser.BlockParser` | Parsers for parsing block level elements. | +| `parser.WithInlineParsers` | A `util.PrioritizedSlice` whose elements are `parser.InlineParser` | Parsers for parsing inline level elements. | +| `parser.WithParagraphTransformers` | A `util.PrioritizedSlice` whose elements are `parser.ParagraphTransformer` | Transformers for transforming paragraph nodes. | +| `parser.WithASTTransformers` | A `util.PrioritizedSlice` whose elements are `parser.ASTTransformer` | Transformers for transforming an AST. | +| `parser.WithAutoHeadingID` | `-` | Enables auto heading ids. | +| `parser.WithAttribute` | `-` | Enables custom attributes. Currently only headings supports attributes. | + +### HTML Renderer options + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `html.WithWriter` | `html.Writer` | `html.Writer` for writing contents to an `io.Writer`. | +| `html.WithHardWraps` | `-` | Render newlines as `
`.| +| `html.WithXHTML` | `-` | Render as XHTML. | +| `html.WithUnsafe` | `-` | By default, goldmark does not render raw HTML or potentially dangerous links. With this option, goldmark renders such content as written. | + +### Built-in extensions + +- `extension.Table` + - [GitHub Flavored Markdown: Tables](https://github.github.com/gfm/#tables-extension-) +- `extension.Strikethrough` + - [GitHub Flavored Markdown: Strikethrough](https://github.github.com/gfm/#strikethrough-extension-) +- `extension.Linkify` + - [GitHub Flavored Markdown: Autolinks](https://github.github.com/gfm/#autolinks-extension-) +- `extension.TaskList` + - [GitHub Flavored Markdown: Task list items](https://github.github.com/gfm/#task-list-items-extension-) +- `extension.GFM` + - This extension enables Table, Strikethrough, Linkify and TaskList. + - This extension does not filter tags defined in [6.11: Disallowed Raw HTML (extension)](https://github.github.com/gfm/#disallowed-raw-html-extension-). + If you need to filter HTML tags, see [Security](#security). + - If you need to parse github emojis, you can use [goldmark-emoji](https://github.com/yuin/goldmark-emoji) extension. +- `extension.DefinitionList` + - [PHP Markdown Extra: Definition lists](https://michelf.ca/projects/php-markdown/extra/#def-list) +- `extension.Footnote` + - [PHP Markdown Extra: Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes) +- `extension.Typographer` + - This extension substitutes punctuations with typographic entities like [smartypants](https://daringfireball.net/projects/smartypants/). + +### Attributes +The `parser.WithAttribute` option allows you to define attributes on some elements. + +Currently only headings support attributes. + +**Attributes are being discussed in the +[CommonMark forum](https://talk.commonmark.org/t/consistent-attribute-syntax/272). +This syntax may possibly change in the future.** + + +#### Headings + +``` +## heading ## {#id .className attrName=attrValue class="class1 class2"} + +## heading {#id .className attrName=attrValue class="class1 class2"} +``` + +``` +heading {#id .className attrName=attrValue} +============ +``` + +### Table extension +The Table extension implements [Table(extension)](https://github.github.com/gfm/#tables-extension-), as +defined in [GitHub Flavored Markdown Spec](https://github.github.com/gfm/). + +Specs are defined for XHTML, so specs use some deprecated attributes for HTML5. + +You can override alignment rendering method via options. + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `extension.WithTableCellAlignMethod` | `extension.TableCellAlignMethod` | Option indicates how are table cells aligned. | + +### Typographer extension + +The Typographer extension translates plain ASCII punctuation characters into typographic-punctuation HTML entities. + +Default substitutions are: + +| Punctuation | Default entity | +| ------------ | ---------- | +| `'` | `‘`, `’` | +| `"` | `“`, `”` | +| `--` | `–` | +| `---` | `—` | +| `...` | `…` | +| `<<` | `«` | +| `>>` | `»` | + +You can override the default substitutions via `extensions.WithTypographicSubstitutions`: + +```go +markdown := goldmark.New( + goldmark.WithExtensions( + extension.NewTypographer( + extension.WithTypographicSubstitutions(extension.TypographicSubstitutions{ + extension.LeftSingleQuote: []byte("‚"), + extension.RightSingleQuote: nil, // nil disables a substitution + }), + ), + ), +) +``` + +### Linkify extension + +The Linkify extension implements [Autolinks(extension)](https://github.github.com/gfm/#autolinks-extension-), as +defined in [GitHub Flavored Markdown Spec](https://github.github.com/gfm/). + +Since the spec does not define details about URLs, there are numerous ambiguous cases. + +You can override autolinking patterns via options. + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `extension.WithLinkifyAllowedProtocols` | `[][]byte` | List of allowed protocols such as `[][]byte{ []byte("http:") }` | +| `extension.WithLinkifyURLRegexp` | `*regexp.Regexp` | Regexp that defines URLs, including protocols | +| `extension.WithLinkifyWWWRegexp` | `*regexp.Regexp` | Regexp that defines URL starting with `www.`. This pattern corresponds to [the extended www autolink](https://github.github.com/gfm/#extended-www-autolink) | +| `extension.WithLinkifyEmailRegexp` | `*regexp.Regexp` | Regexp that defines email addresses` | + +Example, using [xurls](https://github.com/mvdan/xurls): + +```go +import "mvdan.cc/xurls/v2" + +markdown := goldmark.New( + goldmark.WithRendererOptions( + html.WithXHTML(), + html.WithUnsafe(), + ), + goldmark.WithExtensions( + extension.NewLinkify( + extension.WithLinkifyAllowedProtocols([][]byte{ + []byte("http:"), + []byte("https:"), + }), + extension.WithLinkifyURLRegexp( + xurls.Strict, + ), + ), + ), +) +``` + +### Footnotes extension + +The Footnote extension implements [PHP Markdown Extra: Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes). + +This extension has some options: + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `extension.WithFootnoteIDPrefix` | `[]byte` | a prefix for the id attributes.| +| `extension.WithFootnoteIDPrefixFunction` | `func(gast.Node) []byte` | a function that determines the id attribute for given Node.| +| `extension.WithFootnoteLinkTitle` | `[]byte` | an optional title attribute for footnote links.| +| `extension.WithFootnoteBacklinkTitle` | `[]byte` | an optional title attribute for footnote backlinks. | +| `extension.WithFootnoteLinkClass` | `[]byte` | a class for footnote links. This defaults to `footnote-ref`. | +| `extension.WithFootnoteBacklinkClass` | `[]byte` | a class for footnote backlinks. This defaults to `footnote-backref`. | +| `extension.WithFootnoteBacklinkHTML` | `[]byte` | a class for footnote backlinks. This defaults to `↩︎`. | + +Some options can have special substitutions. Occurrences of “^^” in the string will be replaced by the corresponding footnote number in the HTML output. Occurrences of “%%” will be replaced by a number for the reference (footnotes can have multiple references). + +`extension.WithFootnoteIDPrefix` and `extension.WithFootnoteIDPrefixFunction` are useful if you have multiple Markdown documents displayed inside one HTML document to avoid footnote ids to clash each other. + +`extension.WithFootnoteIDPrefix` sets fixed id prefix, so you may write codes like the following: + +```go +for _, path := range files { + source := readAll(path) + prefix := getPrefix(path) + + markdown := goldmark.New( + goldmark.WithExtensions( + NewFootnote( + WithFootnoteIDPrefix([]byte(path)), + ), + ), + ) + var b bytes.Buffer + err := markdown.Convert(source, &b) + if err != nil { + t.Error(err.Error()) + } +} +``` + +`extension.WithFootnoteIDPrefixFunction` determines an id prefix by calling given function, so you may write codes like the following: + +```go +markdown := goldmark.New( + goldmark.WithExtensions( + NewFootnote( + WithFootnoteIDPrefixFunction(func(n gast.Node) []byte { + v, ok := n.OwnerDocument().Meta()["footnote-prefix"] + if ok { + return util.StringToReadOnlyBytes(v.(string)) + } + return nil + }), + ), + ), +) + +for _, path := range files { + source := readAll(path) + var b bytes.Buffer + + doc := markdown.Parser().Parse(text.NewReader(source)) + doc.Meta()["footnote-prefix"] = getPrefix(path) + err := markdown.Renderer().Render(&b, source, doc) +} +``` + +You can use [goldmark-meta](https://github.com/yuin/goldmark-meta) to define a id prefix in the markdown document: + + +```markdown +--- +title: document title +slug: article1 +footnote-prefix: article1 +--- + +# My article + +``` + +Security +-------------------- +By default, goldmark does not render raw HTML or potentially-dangerous URLs. +If you need to gain more control over untrusted contents, it is recommended that you +use an HTML sanitizer such as [bluemonday](https://github.com/microcosm-cc/bluemonday). + +Benchmark +-------------------- +You can run this benchmark in the `_benchmark` directory. + +### against other golang libraries + +blackfriday v2 seems to be the fastest, but as it is not CommonMark compliant, its performance cannot be directly compared to that of the CommonMark-compliant libraries. + +goldmark, meanwhile, builds a clean, extensible AST structure, achieves full compliance with +CommonMark, and consumes less memory, all while being reasonably fast. + +``` +goos: darwin +goarch: amd64 +BenchmarkMarkdown/Blackfriday-v2-12 326 3465240 ns/op 3298861 B/op 20047 allocs/op +BenchmarkMarkdown/GoldMark-12 303 3927494 ns/op 2574809 B/op 13853 allocs/op +BenchmarkMarkdown/CommonMark-12 244 4900853 ns/op 2753851 B/op 20527 allocs/op +BenchmarkMarkdown/Lute-12 130 9195245 ns/op 9175030 B/op 123534 allocs/op +BenchmarkMarkdown/GoMarkdown-12 9 113541994 ns/op 2187472 B/op 22173 allocs/op +``` + +### against cmark (CommonMark reference implementation written in C) + +``` +----------- cmark ----------- +file: _data.md +iteration: 50 +average: 0.0037760639 sec +go run ./goldmark_benchmark.go +------- goldmark ------- +file: _data.md +iteration: 50 +average: 0.0040964230 sec +``` + +As you can see, goldmark's performance is on par with cmark's. + +Extensions +-------------------- + +- [goldmark-meta](https://github.com/yuin/goldmark-meta): A YAML metadata + extension for the goldmark Markdown parser. +- [goldmark-highlighting](https://github.com/yuin/goldmark-highlighting): A syntax-highlighting extension + for the goldmark markdown parser. +- [goldmark-emoji](https://github.com/yuin/goldmark-emoji): An emoji + extension for the goldmark Markdown parser. +- [goldmark-mathjax](https://github.com/litao91/goldmark-mathjax): Mathjax support for the goldmark markdown parser +- [goldmark-pdf](https://github.com/stephenafamo/goldmark-pdf): A PDF renderer that can be passed to `goldmark.WithRenderer()`. + +goldmark internal(for extension developers) +---------------------------------------------- +### Overview +goldmark's Markdown processing is outlined in the diagram below. + +``` + + | + V + +-------- parser.Parser --------------------------- + | 1. Parse block elements into AST + | 1. If a parsed block is a paragraph, apply + | ast.ParagraphTransformer + | 2. Traverse AST and parse blocks. + | 1. Process delimiters(emphasis) at the end of + | block parsing + | 3. Apply parser.ASTTransformers to AST + | + V + + | + V + +------- renderer.Renderer ------------------------ + | 1. Traverse AST and apply renderer.NodeRenderer + | corespond to the node type + + | + V + +``` + +### Parsing +Markdown documents are read through `text.Reader` interface. + +AST nodes do not have concrete text. AST nodes have segment information of the documents, represented by `text.Segment` . + +`text.Segment` has 3 attributes: `Start`, `End`, `Padding` . + +(TBC) + +**TODO** + +See `extension` directory for examples of extensions. + +Summary: + +1. Define AST Node as a struct in which `ast.BaseBlock` or `ast.BaseInline` is embedded. +2. Write a parser that implements `parser.BlockParser` or `parser.InlineParser`. +3. Write a renderer that implements `renderer.NodeRenderer`. +4. Define your goldmark extension that implements `goldmark.Extender`. + + +Donation +-------------------- +BTC: 1NEDSyUmo4SMTDP83JJQSWi1MvQUGGNMZB + +License +-------------------- +MIT + +Author +-------------------- +Yusuke Inuzuka diff --git a/vendor/github.com/yuin/goldmark/ast/ast.go b/vendor/github.com/yuin/goldmark/ast/ast.go new file mode 100644 index 0000000000..3719ebbd8d --- /dev/null +++ b/vendor/github.com/yuin/goldmark/ast/ast.go @@ -0,0 +1,508 @@ +// Package ast defines AST nodes that represent markdown elements. +package ast + +import ( + "bytes" + "fmt" + "strings" + + textm "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +// A NodeType indicates what type a node belongs to. +type NodeType int + +const ( + // TypeBlock indicates that a node is kind of block nodes. + TypeBlock NodeType = iota + 1 + // TypeInline indicates that a node is kind of inline nodes. + TypeInline + // TypeDocument indicates that a node is kind of document nodes. + TypeDocument +) + +// NodeKind indicates more specific type than NodeType. +type NodeKind int + +func (k NodeKind) String() string { + return kindNames[k] +} + +var kindMax NodeKind +var kindNames = []string{""} + +// NewNodeKind returns a new Kind value. +func NewNodeKind(name string) NodeKind { + kindMax++ + kindNames = append(kindNames, name) + return kindMax +} + +// An Attribute is an attribute of the Node +type Attribute struct { + Name []byte + Value interface{} +} + +// A Node interface defines basic AST node functionalities. +type Node interface { + // Type returns a type of this node. + Type() NodeType + + // Kind returns a kind of this node. + Kind() NodeKind + + // NextSibling returns a next sibling node of this node. + NextSibling() Node + + // PreviousSibling returns a previous sibling node of this node. + PreviousSibling() Node + + // Parent returns a parent node of this node. + Parent() Node + + // SetParent sets a parent node to this node. + SetParent(Node) + + // SetPreviousSibling sets a previous sibling node to this node. + SetPreviousSibling(Node) + + // SetNextSibling sets a next sibling node to this node. + SetNextSibling(Node) + + // HasChildren returns true if this node has any children, otherwise false. + HasChildren() bool + + // ChildCount returns a total number of children. + ChildCount() int + + // FirstChild returns a first child of this node. + FirstChild() Node + + // LastChild returns a last child of this node. + LastChild() Node + + // AppendChild append a node child to the tail of the children. + AppendChild(self, child Node) + + // RemoveChild removes a node child from this node. + // If a node child is not children of this node, RemoveChild nothing to do. + RemoveChild(self, child Node) + + // RemoveChildren removes all children from this node. + RemoveChildren(self Node) + + // SortChildren sorts childrens by comparator. + SortChildren(comparator func(n1, n2 Node) int) + + // ReplaceChild replace a node v1 with a node insertee. + // If v1 is not children of this node, ReplaceChild append a insetee to the + // tail of the children. + ReplaceChild(self, v1, insertee Node) + + // InsertBefore inserts a node insertee before a node v1. + // If v1 is not children of this node, InsertBefore append a insetee to the + // tail of the children. + InsertBefore(self, v1, insertee Node) + + // InsertAfterinserts a node insertee after a node v1. + // If v1 is not children of this node, InsertBefore append a insetee to the + // tail of the children. + InsertAfter(self, v1, insertee Node) + + // OwnerDocument returns this node's owner document. + // If this node is not a child of the Document node, OwnerDocument + // returns nil. + OwnerDocument() *Document + + // Dump dumps an AST tree structure to stdout. + // This function completely aimed for debugging. + // level is a indent level. Implementer should indent informations with + // 2 * level spaces. + Dump(source []byte, level int) + + // Text returns text values of this node. + Text(source []byte) []byte + + // HasBlankPreviousLines returns true if the row before this node is blank, + // otherwise false. + // This method is valid only for block nodes. + HasBlankPreviousLines() bool + + // SetBlankPreviousLines sets whether the row before this node is blank. + // This method is valid only for block nodes. + SetBlankPreviousLines(v bool) + + // Lines returns text segments that hold positions in a source. + // This method is valid only for block nodes. + Lines() *textm.Segments + + // SetLines sets text segments that hold positions in a source. + // This method is valid only for block nodes. + SetLines(*textm.Segments) + + // IsRaw returns true if contents should be rendered as 'raw' contents. + IsRaw() bool + + // SetAttribute sets the given value to the attributes. + SetAttribute(name []byte, value interface{}) + + // SetAttributeString sets the given value to the attributes. + SetAttributeString(name string, value interface{}) + + // Attribute returns a (attribute value, true) if an attribute + // associated with the given name is found, otherwise + // (nil, false) + Attribute(name []byte) (interface{}, bool) + + // AttributeString returns a (attribute value, true) if an attribute + // associated with the given name is found, otherwise + // (nil, false) + AttributeString(name string) (interface{}, bool) + + // Attributes returns a list of attributes. + // This may be a nil if there are no attributes. + Attributes() []Attribute + + // RemoveAttributes removes all attributes from this node. + RemoveAttributes() +} + +// A BaseNode struct implements the Node interface partialliy. +type BaseNode struct { + firstChild Node + lastChild Node + parent Node + next Node + prev Node + childCount int + attributes []Attribute +} + +func ensureIsolated(v Node) { + if p := v.Parent(); p != nil { + p.RemoveChild(p, v) + } +} + +// HasChildren implements Node.HasChildren . +func (n *BaseNode) HasChildren() bool { + return n.firstChild != nil +} + +// SetPreviousSibling implements Node.SetPreviousSibling . +func (n *BaseNode) SetPreviousSibling(v Node) { + n.prev = v +} + +// SetNextSibling implements Node.SetNextSibling . +func (n *BaseNode) SetNextSibling(v Node) { + n.next = v +} + +// PreviousSibling implements Node.PreviousSibling . +func (n *BaseNode) PreviousSibling() Node { + return n.prev +} + +// NextSibling implements Node.NextSibling . +func (n *BaseNode) NextSibling() Node { + return n.next +} + +// RemoveChild implements Node.RemoveChild . +func (n *BaseNode) RemoveChild(self, v Node) { + if v.Parent() != self { + return + } + n.childCount-- + prev := v.PreviousSibling() + next := v.NextSibling() + if prev != nil { + prev.SetNextSibling(next) + } else { + n.firstChild = next + } + if next != nil { + next.SetPreviousSibling(prev) + } else { + n.lastChild = prev + } + v.SetParent(nil) + v.SetPreviousSibling(nil) + v.SetNextSibling(nil) +} + +// RemoveChildren implements Node.RemoveChildren . +func (n *BaseNode) RemoveChildren(self Node) { + for c := n.firstChild; c != nil; { + c.SetParent(nil) + c.SetPreviousSibling(nil) + next := c.NextSibling() + c.SetNextSibling(nil) + c = next + } + n.firstChild = nil + n.lastChild = nil + n.childCount = 0 +} + +// SortChildren implements Node.SortChildren +func (n *BaseNode) SortChildren(comparator func(n1, n2 Node) int) { + var sorted Node + current := n.firstChild + for current != nil { + next := current.NextSibling() + if sorted == nil || comparator(sorted, current) >= 0 { + current.SetNextSibling(sorted) + if sorted != nil { + sorted.SetPreviousSibling(current) + } + sorted = current + sorted.SetPreviousSibling(nil) + } else { + c := sorted + for c.NextSibling() != nil && comparator(c.NextSibling(), current) < 0 { + c = c.NextSibling() + } + current.SetNextSibling(c.NextSibling()) + current.SetPreviousSibling(c) + if c.NextSibling() != nil { + c.NextSibling().SetPreviousSibling(current) + } + c.SetNextSibling(current) + } + current = next + } + n.firstChild = sorted + for c := n.firstChild; c != nil; c = c.NextSibling() { + n.lastChild = c + } +} + +// FirstChild implements Node.FirstChild . +func (n *BaseNode) FirstChild() Node { + return n.firstChild +} + +// LastChild implements Node.LastChild . +func (n *BaseNode) LastChild() Node { + return n.lastChild +} + +// ChildCount implements Node.ChildCount . +func (n *BaseNode) ChildCount() int { + return n.childCount +} + +// Parent implements Node.Parent . +func (n *BaseNode) Parent() Node { + return n.parent +} + +// SetParent implements Node.SetParent . +func (n *BaseNode) SetParent(v Node) { + n.parent = v +} + +// AppendChild implements Node.AppendChild . +func (n *BaseNode) AppendChild(self, v Node) { + ensureIsolated(v) + if n.firstChild == nil { + n.firstChild = v + v.SetNextSibling(nil) + v.SetPreviousSibling(nil) + } else { + last := n.lastChild + last.SetNextSibling(v) + v.SetPreviousSibling(last) + } + v.SetParent(self) + n.lastChild = v + n.childCount++ +} + +// ReplaceChild implements Node.ReplaceChild . +func (n *BaseNode) ReplaceChild(self, v1, insertee Node) { + n.InsertBefore(self, v1, insertee) + n.RemoveChild(self, v1) +} + +// InsertAfter implements Node.InsertAfter . +func (n *BaseNode) InsertAfter(self, v1, insertee Node) { + n.InsertBefore(self, v1.NextSibling(), insertee) +} + +// InsertBefore implements Node.InsertBefore . +func (n *BaseNode) InsertBefore(self, v1, insertee Node) { + n.childCount++ + if v1 == nil { + n.AppendChild(self, insertee) + return + } + ensureIsolated(insertee) + if v1.Parent() == self { + c := v1 + prev := c.PreviousSibling() + if prev != nil { + prev.SetNextSibling(insertee) + insertee.SetPreviousSibling(prev) + } else { + n.firstChild = insertee + insertee.SetPreviousSibling(nil) + } + insertee.SetNextSibling(c) + c.SetPreviousSibling(insertee) + insertee.SetParent(self) + } +} + +// OwnerDocument implements Node.OwnerDocument +func (n *BaseNode) OwnerDocument() *Document { + d := n.Parent() + for { + p := d.Parent() + if p == nil { + if v, ok := d.(*Document); ok { + return v + } + break + } + d = p + } + return nil +} + +// Text implements Node.Text . +func (n *BaseNode) Text(source []byte) []byte { + var buf bytes.Buffer + for c := n.firstChild; c != nil; c = c.NextSibling() { + buf.Write(c.Text(source)) + } + return buf.Bytes() +} + +// SetAttribute implements Node.SetAttribute. +func (n *BaseNode) SetAttribute(name []byte, value interface{}) { + if n.attributes == nil { + n.attributes = make([]Attribute, 0, 10) + } else { + for i, a := range n.attributes { + if bytes.Equal(a.Name, name) { + n.attributes[i].Name = name + n.attributes[i].Value = value + return + } + } + } + n.attributes = append(n.attributes, Attribute{name, value}) +} + +// SetAttributeString implements Node.SetAttributeString +func (n *BaseNode) SetAttributeString(name string, value interface{}) { + n.SetAttribute(util.StringToReadOnlyBytes(name), value) +} + +// Attribute implements Node.Attribute. +func (n *BaseNode) Attribute(name []byte) (interface{}, bool) { + if n.attributes == nil { + return nil, false + } + for i, a := range n.attributes { + if bytes.Equal(a.Name, name) { + return n.attributes[i].Value, true + } + } + return nil, false +} + +// AttributeString implements Node.AttributeString. +func (n *BaseNode) AttributeString(s string) (interface{}, bool) { + return n.Attribute(util.StringToReadOnlyBytes(s)) +} + +// Attributes implements Node.Attributes +func (n *BaseNode) Attributes() []Attribute { + return n.attributes +} + +// RemoveAttributes implements Node.RemoveAttributes +func (n *BaseNode) RemoveAttributes() { + n.attributes = nil +} + +// DumpHelper is a helper function to implement Node.Dump. +// kv is pairs of an attribute name and an attribute value. +// cb is a function called after wrote a name and attributes. +func DumpHelper(v Node, source []byte, level int, kv map[string]string, cb func(int)) { + name := v.Kind().String() + indent := strings.Repeat(" ", level) + fmt.Printf("%s%s {\n", indent, name) + indent2 := strings.Repeat(" ", level+1) + if v.Type() == TypeBlock { + fmt.Printf("%sRawText: \"", indent2) + for i := 0; i < v.Lines().Len(); i++ { + line := v.Lines().At(i) + fmt.Printf("%s", line.Value(source)) + } + fmt.Printf("\"\n") + fmt.Printf("%sHasBlankPreviousLines: %v\n", indent2, v.HasBlankPreviousLines()) + } + for name, value := range kv { + fmt.Printf("%s%s: %s\n", indent2, name, value) + } + if cb != nil { + cb(level + 1) + } + for c := v.FirstChild(); c != nil; c = c.NextSibling() { + c.Dump(source, level+1) + } + fmt.Printf("%s}\n", indent) +} + +// WalkStatus represents a current status of the Walk function. +type WalkStatus int + +const ( + // WalkStop indicates no more walking needed. + WalkStop WalkStatus = iota + 1 + + // WalkSkipChildren indicates that Walk wont walk on children of current + // node. + WalkSkipChildren + + // WalkContinue indicates that Walk can continue to walk. + WalkContinue +) + +// Walker is a function that will be called when Walk find a +// new node. +// entering is set true before walks children, false after walked children. +// If Walker returns error, Walk function immediately stop walking. +type Walker func(n Node, entering bool) (WalkStatus, error) + +// Walk walks a AST tree by the depth first search algorithm. +func Walk(n Node, walker Walker) error { + _, err := walkHelper(n, walker) + return err +} + +func walkHelper(n Node, walker Walker) (WalkStatus, error) { + status, err := walker(n, true) + if err != nil || status == WalkStop { + return status, err + } + if status != WalkSkipChildren { + for c := n.FirstChild(); c != nil; c = c.NextSibling() { + if st, err := walkHelper(c, walker); err != nil || st == WalkStop { + return WalkStop, err + } + } + } + status, err = walker(n, false) + if err != nil || status == WalkStop { + return WalkStop, err + } + return WalkContinue, nil +} diff --git a/vendor/github.com/yuin/goldmark/ast/block.go b/vendor/github.com/yuin/goldmark/ast/block.go new file mode 100644 index 0000000000..fc0b3c2e02 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/ast/block.go @@ -0,0 +1,495 @@ +package ast + +import ( + "fmt" + "strings" + + textm "github.com/yuin/goldmark/text" +) + +// A BaseBlock struct implements the Node interface partialliy. +type BaseBlock struct { + BaseNode + blankPreviousLines bool + lines *textm.Segments +} + +// Type implements Node.Type +func (b *BaseBlock) Type() NodeType { + return TypeBlock +} + +// IsRaw implements Node.IsRaw +func (b *BaseBlock) IsRaw() bool { + return false +} + +// HasBlankPreviousLines implements Node.HasBlankPreviousLines. +func (b *BaseBlock) HasBlankPreviousLines() bool { + return b.blankPreviousLines +} + +// SetBlankPreviousLines implements Node.SetBlankPreviousLines. +func (b *BaseBlock) SetBlankPreviousLines(v bool) { + b.blankPreviousLines = v +} + +// Lines implements Node.Lines +func (b *BaseBlock) Lines() *textm.Segments { + if b.lines == nil { + b.lines = textm.NewSegments() + } + return b.lines +} + +// SetLines implements Node.SetLines +func (b *BaseBlock) SetLines(v *textm.Segments) { + b.lines = v +} + +// A Document struct is a root node of Markdown text. +type Document struct { + BaseBlock + + meta map[string]interface{} +} + +// KindDocument is a NodeKind of the Document node. +var KindDocument = NewNodeKind("Document") + +// Dump implements Node.Dump . +func (n *Document) Dump(source []byte, level int) { + DumpHelper(n, source, level, nil, nil) +} + +// Type implements Node.Type . +func (n *Document) Type() NodeType { + return TypeDocument +} + +// Kind implements Node.Kind. +func (n *Document) Kind() NodeKind { + return KindDocument +} + +// OwnerDocument implements Node.OwnerDocument +func (n *Document) OwnerDocument() *Document { + return n +} + +// Meta returns metadata of this document. +func (n *Document) Meta() map[string]interface{} { + if n.meta == nil { + n.meta = map[string]interface{}{} + } + return n.meta +} + +// SetMeta sets given metadata to this document. +func (n *Document) SetMeta(meta map[string]interface{}) { + n.meta = meta +} + +// NewDocument returns a new Document node. +func NewDocument() *Document { + return &Document{ + BaseBlock: BaseBlock{}, + meta: nil, + } +} + +// A TextBlock struct is a node whose lines +// should be rendered without any containers. +type TextBlock struct { + BaseBlock +} + +// Dump implements Node.Dump . +func (n *TextBlock) Dump(source []byte, level int) { + DumpHelper(n, source, level, nil, nil) +} + +// KindTextBlock is a NodeKind of the TextBlock node. +var KindTextBlock = NewNodeKind("TextBlock") + +// Kind implements Node.Kind. +func (n *TextBlock) Kind() NodeKind { + return KindTextBlock +} + +// NewTextBlock returns a new TextBlock node. +func NewTextBlock() *TextBlock { + return &TextBlock{ + BaseBlock: BaseBlock{}, + } +} + +// A Paragraph struct represents a paragraph of Markdown text. +type Paragraph struct { + BaseBlock +} + +// Dump implements Node.Dump . +func (n *Paragraph) Dump(source []byte, level int) { + DumpHelper(n, source, level, nil, nil) +} + +// KindParagraph is a NodeKind of the Paragraph node. +var KindParagraph = NewNodeKind("Paragraph") + +// Kind implements Node.Kind. +func (n *Paragraph) Kind() NodeKind { + return KindParagraph +} + +// NewParagraph returns a new Paragraph node. +func NewParagraph() *Paragraph { + return &Paragraph{ + BaseBlock: BaseBlock{}, + } +} + +// IsParagraph returns true if the given node implements the Paragraph interface, +// otherwise false. +func IsParagraph(node Node) bool { + _, ok := node.(*Paragraph) + return ok +} + +// A Heading struct represents headings like SetextHeading and ATXHeading. +type Heading struct { + BaseBlock + // Level returns a level of this heading. + // This value is between 1 and 6. + Level int +} + +// Dump implements Node.Dump . +func (n *Heading) Dump(source []byte, level int) { + m := map[string]string{ + "Level": fmt.Sprintf("%d", n.Level), + } + DumpHelper(n, source, level, m, nil) +} + +// KindHeading is a NodeKind of the Heading node. +var KindHeading = NewNodeKind("Heading") + +// Kind implements Node.Kind. +func (n *Heading) Kind() NodeKind { + return KindHeading +} + +// NewHeading returns a new Heading node. +func NewHeading(level int) *Heading { + return &Heading{ + BaseBlock: BaseBlock{}, + Level: level, + } +} + +// A ThematicBreak struct represents a thematic break of Markdown text. +type ThematicBreak struct { + BaseBlock +} + +// Dump implements Node.Dump . +func (n *ThematicBreak) Dump(source []byte, level int) { + DumpHelper(n, source, level, nil, nil) +} + +// KindThematicBreak is a NodeKind of the ThematicBreak node. +var KindThematicBreak = NewNodeKind("ThematicBreak") + +// Kind implements Node.Kind. +func (n *ThematicBreak) Kind() NodeKind { + return KindThematicBreak +} + +// NewThematicBreak returns a new ThematicBreak node. +func NewThematicBreak() *ThematicBreak { + return &ThematicBreak{ + BaseBlock: BaseBlock{}, + } +} + +// A CodeBlock interface represents an indented code block of Markdown text. +type CodeBlock struct { + BaseBlock +} + +// IsRaw implements Node.IsRaw. +func (n *CodeBlock) IsRaw() bool { + return true +} + +// Dump implements Node.Dump . +func (n *CodeBlock) Dump(source []byte, level int) { + DumpHelper(n, source, level, nil, nil) +} + +// KindCodeBlock is a NodeKind of the CodeBlock node. +var KindCodeBlock = NewNodeKind("CodeBlock") + +// Kind implements Node.Kind. +func (n *CodeBlock) Kind() NodeKind { + return KindCodeBlock +} + +// NewCodeBlock returns a new CodeBlock node. +func NewCodeBlock() *CodeBlock { + return &CodeBlock{ + BaseBlock: BaseBlock{}, + } +} + +// A FencedCodeBlock struct represents a fenced code block of Markdown text. +type FencedCodeBlock struct { + BaseBlock + // Info returns a info text of this fenced code block. + Info *Text + + language []byte +} + +// Language returns an language in an info string. +// Language returns nil if this node does not have an info string. +func (n *FencedCodeBlock) Language(source []byte) []byte { + if n.language == nil && n.Info != nil { + segment := n.Info.Segment + info := segment.Value(source) + i := 0 + for ; i < len(info); i++ { + if info[i] == ' ' { + break + } + } + n.language = info[:i] + } + return n.language +} + +// IsRaw implements Node.IsRaw. +func (n *FencedCodeBlock) IsRaw() bool { + return true +} + +// Dump implements Node.Dump . +func (n *FencedCodeBlock) Dump(source []byte, level int) { + m := map[string]string{} + if n.Info != nil { + m["Info"] = fmt.Sprintf("\"%s\"", n.Info.Text(source)) + } + DumpHelper(n, source, level, m, nil) +} + +// KindFencedCodeBlock is a NodeKind of the FencedCodeBlock node. +var KindFencedCodeBlock = NewNodeKind("FencedCodeBlock") + +// Kind implements Node.Kind. +func (n *FencedCodeBlock) Kind() NodeKind { + return KindFencedCodeBlock +} + +// NewFencedCodeBlock return a new FencedCodeBlock node. +func NewFencedCodeBlock(info *Text) *FencedCodeBlock { + return &FencedCodeBlock{ + BaseBlock: BaseBlock{}, + Info: info, + } +} + +// A Blockquote struct represents an blockquote block of Markdown text. +type Blockquote struct { + BaseBlock +} + +// Dump implements Node.Dump . +func (n *Blockquote) Dump(source []byte, level int) { + DumpHelper(n, source, level, nil, nil) +} + +// KindBlockquote is a NodeKind of the Blockquote node. +var KindBlockquote = NewNodeKind("Blockquote") + +// Kind implements Node.Kind. +func (n *Blockquote) Kind() NodeKind { + return KindBlockquote +} + +// NewBlockquote returns a new Blockquote node. +func NewBlockquote() *Blockquote { + return &Blockquote{ + BaseBlock: BaseBlock{}, + } +} + +// A List struct represents a list of Markdown text. +type List struct { + BaseBlock + + // Marker is a marker character like '-', '+', ')' and '.'. + Marker byte + + // IsTight is a true if this list is a 'tight' list. + // See https://spec.commonmark.org/0.29/#loose for details. + IsTight bool + + // Start is an initial number of this ordered list. + // If this list is not an ordered list, Start is 0. + Start int +} + +// IsOrdered returns true if this list is an ordered list, otherwise false. +func (l *List) IsOrdered() bool { + return l.Marker == '.' || l.Marker == ')' +} + +// CanContinue returns true if this list can continue with +// the given mark and a list type, otherwise false. +func (l *List) CanContinue(marker byte, isOrdered bool) bool { + return marker == l.Marker && isOrdered == l.IsOrdered() +} + +// Dump implements Node.Dump. +func (l *List) Dump(source []byte, level int) { + m := map[string]string{ + "Ordered": fmt.Sprintf("%v", l.IsOrdered()), + "Marker": fmt.Sprintf("%c", l.Marker), + "Tight": fmt.Sprintf("%v", l.IsTight), + } + if l.IsOrdered() { + m["Start"] = fmt.Sprintf("%d", l.Start) + } + DumpHelper(l, source, level, m, nil) +} + +// KindList is a NodeKind of the List node. +var KindList = NewNodeKind("List") + +// Kind implements Node.Kind. +func (l *List) Kind() NodeKind { + return KindList +} + +// NewList returns a new List node. +func NewList(marker byte) *List { + return &List{ + BaseBlock: BaseBlock{}, + Marker: marker, + IsTight: true, + } +} + +// A ListItem struct represents a list item of Markdown text. +type ListItem struct { + BaseBlock + + // Offset is an offset position of this item. + Offset int +} + +// Dump implements Node.Dump. +func (n *ListItem) Dump(source []byte, level int) { + m := map[string]string{ + "Offset": fmt.Sprintf("%d", n.Offset), + } + DumpHelper(n, source, level, m, nil) +} + +// KindListItem is a NodeKind of the ListItem node. +var KindListItem = NewNodeKind("ListItem") + +// Kind implements Node.Kind. +func (n *ListItem) Kind() NodeKind { + return KindListItem +} + +// NewListItem returns a new ListItem node. +func NewListItem(offset int) *ListItem { + return &ListItem{ + BaseBlock: BaseBlock{}, + Offset: offset, + } +} + +// HTMLBlockType represents kinds of an html blocks. +// See https://spec.commonmark.org/0.29/#html-blocks +type HTMLBlockType int + +const ( + // HTMLBlockType1 represents type 1 html blocks + HTMLBlockType1 HTMLBlockType = iota + 1 + // HTMLBlockType2 represents type 2 html blocks + HTMLBlockType2 + // HTMLBlockType3 represents type 3 html blocks + HTMLBlockType3 + // HTMLBlockType4 represents type 4 html blocks + HTMLBlockType4 + // HTMLBlockType5 represents type 5 html blocks + HTMLBlockType5 + // HTMLBlockType6 represents type 6 html blocks + HTMLBlockType6 + // HTMLBlockType7 represents type 7 html blocks + HTMLBlockType7 +) + +// An HTMLBlock struct represents an html block of Markdown text. +type HTMLBlock struct { + BaseBlock + + // Type is a type of this html block. + HTMLBlockType HTMLBlockType + + // ClosureLine is a line that closes this html block. + ClosureLine textm.Segment +} + +// IsRaw implements Node.IsRaw. +func (n *HTMLBlock) IsRaw() bool { + return true +} + +// HasClosure returns true if this html block has a closure line, +// otherwise false. +func (n *HTMLBlock) HasClosure() bool { + return n.ClosureLine.Start >= 0 +} + +// Dump implements Node.Dump. +func (n *HTMLBlock) Dump(source []byte, level int) { + indent := strings.Repeat(" ", level) + fmt.Printf("%s%s {\n", indent, "HTMLBlock") + indent2 := strings.Repeat(" ", level+1) + fmt.Printf("%sRawText: \"", indent2) + for i := 0; i < n.Lines().Len(); i++ { + s := n.Lines().At(i) + fmt.Print(string(source[s.Start:s.Stop])) + } + fmt.Printf("\"\n") + for c := n.FirstChild(); c != nil; c = c.NextSibling() { + c.Dump(source, level+1) + } + if n.HasClosure() { + cl := n.ClosureLine + fmt.Printf("%sClosure: \"%s\"\n", indent2, string(cl.Value(source))) + } + fmt.Printf("%s}\n", indent) +} + +// KindHTMLBlock is a NodeKind of the HTMLBlock node. +var KindHTMLBlock = NewNodeKind("HTMLBlock") + +// Kind implements Node.Kind. +func (n *HTMLBlock) Kind() NodeKind { + return KindHTMLBlock +} + +// NewHTMLBlock returns a new HTMLBlock node. +func NewHTMLBlock(typ HTMLBlockType) *HTMLBlock { + return &HTMLBlock{ + BaseBlock: BaseBlock{}, + HTMLBlockType: typ, + ClosureLine: textm.NewSegment(-1, -1), + } +} diff --git a/vendor/github.com/yuin/goldmark/ast/inline.go b/vendor/github.com/yuin/goldmark/ast/inline.go new file mode 100644 index 0000000000..b221695bd7 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/ast/inline.go @@ -0,0 +1,548 @@ +package ast + +import ( + "fmt" + "strings" + + textm "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +// A BaseInline struct implements the Node interface partialliy. +type BaseInline struct { + BaseNode +} + +// Type implements Node.Type +func (b *BaseInline) Type() NodeType { + return TypeInline +} + +// IsRaw implements Node.IsRaw +func (b *BaseInline) IsRaw() bool { + return false +} + +// HasBlankPreviousLines implements Node.HasBlankPreviousLines. +func (b *BaseInline) HasBlankPreviousLines() bool { + panic("can not call with inline nodes.") +} + +// SetBlankPreviousLines implements Node.SetBlankPreviousLines. +func (b *BaseInline) SetBlankPreviousLines(v bool) { + panic("can not call with inline nodes.") +} + +// Lines implements Node.Lines +func (b *BaseInline) Lines() *textm.Segments { + panic("can not call with inline nodes.") +} + +// SetLines implements Node.SetLines +func (b *BaseInline) SetLines(v *textm.Segments) { + panic("can not call with inline nodes.") +} + +// A Text struct represents a textual content of the Markdown text. +type Text struct { + BaseInline + // Segment is a position in a source text. + Segment textm.Segment + + flags uint8 +} + +const ( + textSoftLineBreak = 1 << iota + textHardLineBreak + textRaw + textCode +) + +func textFlagsString(flags uint8) string { + buf := []string{} + if flags&textSoftLineBreak != 0 { + buf = append(buf, "SoftLineBreak") + } + if flags&textHardLineBreak != 0 { + buf = append(buf, "HardLineBreak") + } + if flags&textRaw != 0 { + buf = append(buf, "Raw") + } + if flags&textCode != 0 { + buf = append(buf, "Code") + } + return strings.Join(buf, ", ") +} + +// Inline implements Inline.Inline. +func (n *Text) Inline() { +} + +// SoftLineBreak returns true if this node ends with a new line, +// otherwise false. +func (n *Text) SoftLineBreak() bool { + return n.flags&textSoftLineBreak != 0 +} + +// SetSoftLineBreak sets whether this node ends with a new line. +func (n *Text) SetSoftLineBreak(v bool) { + if v { + n.flags |= textSoftLineBreak + } else { + n.flags = n.flags &^ textHardLineBreak + } +} + +// IsRaw returns true if this text should be rendered without unescaping +// back slash escapes and resolving references. +func (n *Text) IsRaw() bool { + return n.flags&textRaw != 0 +} + +// SetRaw sets whether this text should be rendered as raw contents. +func (n *Text) SetRaw(v bool) { + if v { + n.flags |= textRaw + } else { + n.flags = n.flags &^ textRaw + } +} + +// HardLineBreak returns true if this node ends with a hard line break. +// See https://spec.commonmark.org/0.29/#hard-line-breaks for details. +func (n *Text) HardLineBreak() bool { + return n.flags&textHardLineBreak != 0 +} + +// SetHardLineBreak sets whether this node ends with a hard line break. +func (n *Text) SetHardLineBreak(v bool) { + if v { + n.flags |= textHardLineBreak + } else { + n.flags = n.flags &^ textHardLineBreak + } +} + +// Merge merges a Node n into this node. +// Merge returns true if the given node has been merged, otherwise false. +func (n *Text) Merge(node Node, source []byte) bool { + t, ok := node.(*Text) + if !ok { + return false + } + if n.Segment.Stop != t.Segment.Start || t.Segment.Padding != 0 || source[n.Segment.Stop-1] == '\n' || t.IsRaw() != n.IsRaw() { + return false + } + n.Segment.Stop = t.Segment.Stop + n.SetSoftLineBreak(t.SoftLineBreak()) + n.SetHardLineBreak(t.HardLineBreak()) + return true +} + +// Text implements Node.Text. +func (n *Text) Text(source []byte) []byte { + return n.Segment.Value(source) +} + +// Dump implements Node.Dump. +func (n *Text) Dump(source []byte, level int) { + fs := textFlagsString(n.flags) + if len(fs) != 0 { + fs = "(" + fs + ")" + } + fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n")) +} + +// KindText is a NodeKind of the Text node. +var KindText = NewNodeKind("Text") + +// Kind implements Node.Kind. +func (n *Text) Kind() NodeKind { + return KindText +} + +// NewText returns a new Text node. +func NewText() *Text { + return &Text{ + BaseInline: BaseInline{}, + } +} + +// NewTextSegment returns a new Text node with the given source position. +func NewTextSegment(v textm.Segment) *Text { + return &Text{ + BaseInline: BaseInline{}, + Segment: v, + } +} + +// NewRawTextSegment returns a new Text node with the given source position. +// The new node should be rendered as raw contents. +func NewRawTextSegment(v textm.Segment) *Text { + t := &Text{ + BaseInline: BaseInline{}, + Segment: v, + } + t.SetRaw(true) + return t +} + +// MergeOrAppendTextSegment merges a given s into the last child of the parent if +// it can be merged, otherwise creates a new Text node and appends it to after current +// last child. +func MergeOrAppendTextSegment(parent Node, s textm.Segment) { + last := parent.LastChild() + t, ok := last.(*Text) + if ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() { + t.Segment = t.Segment.WithStop(s.Stop) + } else { + parent.AppendChild(parent, NewTextSegment(s)) + } +} + +// MergeOrReplaceTextSegment merges a given s into a previous sibling of the node n +// if a previous sibling of the node n is *Text, otherwise replaces Node n with s. +func MergeOrReplaceTextSegment(parent Node, n Node, s textm.Segment) { + prev := n.PreviousSibling() + if t, ok := prev.(*Text); ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() { + t.Segment = t.Segment.WithStop(s.Stop) + parent.RemoveChild(parent, n) + } else { + parent.ReplaceChild(parent, n, NewTextSegment(s)) + } +} + +// A String struct is a textual content that has a concrete value +type String struct { + BaseInline + + Value []byte + flags uint8 +} + +// Inline implements Inline.Inline. +func (n *String) Inline() { +} + +// IsRaw returns true if this text should be rendered without unescaping +// back slash escapes and resolving references. +func (n *String) IsRaw() bool { + return n.flags&textRaw != 0 +} + +// SetRaw sets whether this text should be rendered as raw contents. +func (n *String) SetRaw(v bool) { + if v { + n.flags |= textRaw + } else { + n.flags = n.flags &^ textRaw + } +} + +// IsCode returns true if this text should be rendered without any +// modifications. +func (n *String) IsCode() bool { + return n.flags&textCode != 0 +} + +// SetCode sets whether this text should be rendered without any modifications. +func (n *String) SetCode(v bool) { + if v { + n.flags |= textCode + } else { + n.flags = n.flags &^ textCode + } +} + +// Text implements Node.Text. +func (n *String) Text(source []byte) []byte { + return n.Value +} + +// Dump implements Node.Dump. +func (n *String) Dump(source []byte, level int) { + fs := textFlagsString(n.flags) + if len(fs) != 0 { + fs = "(" + fs + ")" + } + fmt.Printf("%sString%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value), "\n")) +} + +// KindString is a NodeKind of the String node. +var KindString = NewNodeKind("String") + +// Kind implements Node.Kind. +func (n *String) Kind() NodeKind { + return KindString +} + +// NewString returns a new String node. +func NewString(v []byte) *String { + return &String{ + Value: v, + } +} + +// A CodeSpan struct represents a code span of Markdown text. +type CodeSpan struct { + BaseInline +} + +// Inline implements Inline.Inline . +func (n *CodeSpan) Inline() { +} + +// IsBlank returns true if this node consists of spaces, otherwise false. +func (n *CodeSpan) IsBlank(source []byte) bool { + for c := n.FirstChild(); c != nil; c = c.NextSibling() { + text := c.(*Text).Segment + if !util.IsBlank(text.Value(source)) { + return false + } + } + return true +} + +// Dump implements Node.Dump +func (n *CodeSpan) Dump(source []byte, level int) { + DumpHelper(n, source, level, nil, nil) +} + +// KindCodeSpan is a NodeKind of the CodeSpan node. +var KindCodeSpan = NewNodeKind("CodeSpan") + +// Kind implements Node.Kind. +func (n *CodeSpan) Kind() NodeKind { + return KindCodeSpan +} + +// NewCodeSpan returns a new CodeSpan node. +func NewCodeSpan() *CodeSpan { + return &CodeSpan{ + BaseInline: BaseInline{}, + } +} + +// An Emphasis struct represents an emphasis of Markdown text. +type Emphasis struct { + BaseInline + + // Level is a level of the emphasis. + Level int +} + +// Dump implements Node.Dump. +func (n *Emphasis) Dump(source []byte, level int) { + m := map[string]string{ + "Level": fmt.Sprintf("%v", n.Level), + } + DumpHelper(n, source, level, m, nil) +} + +// KindEmphasis is a NodeKind of the Emphasis node. +var KindEmphasis = NewNodeKind("Emphasis") + +// Kind implements Node.Kind. +func (n *Emphasis) Kind() NodeKind { + return KindEmphasis +} + +// NewEmphasis returns a new Emphasis node with the given level. +func NewEmphasis(level int) *Emphasis { + return &Emphasis{ + BaseInline: BaseInline{}, + Level: level, + } +} + +type baseLink struct { + BaseInline + + // Destination is a destination(URL) of this link. + Destination []byte + + // Title is a title of this link. + Title []byte +} + +// Inline implements Inline.Inline. +func (n *baseLink) Inline() { +} + +// A Link struct represents a link of the Markdown text. +type Link struct { + baseLink +} + +// Dump implements Node.Dump. +func (n *Link) Dump(source []byte, level int) { + m := map[string]string{} + m["Destination"] = string(n.Destination) + m["Title"] = string(n.Title) + DumpHelper(n, source, level, m, nil) +} + +// KindLink is a NodeKind of the Link node. +var KindLink = NewNodeKind("Link") + +// Kind implements Node.Kind. +func (n *Link) Kind() NodeKind { + return KindLink +} + +// NewLink returns a new Link node. +func NewLink() *Link { + c := &Link{ + baseLink: baseLink{ + BaseInline: BaseInline{}, + }, + } + return c +} + +// An Image struct represents an image of the Markdown text. +type Image struct { + baseLink +} + +// Dump implements Node.Dump. +func (n *Image) Dump(source []byte, level int) { + m := map[string]string{} + m["Destination"] = string(n.Destination) + m["Title"] = string(n.Title) + DumpHelper(n, source, level, m, nil) +} + +// KindImage is a NodeKind of the Image node. +var KindImage = NewNodeKind("Image") + +// Kind implements Node.Kind. +func (n *Image) Kind() NodeKind { + return KindImage +} + +// NewImage returns a new Image node. +func NewImage(link *Link) *Image { + c := &Image{ + baseLink: baseLink{ + BaseInline: BaseInline{}, + }, + } + c.Destination = link.Destination + c.Title = link.Title + for n := link.FirstChild(); n != nil; { + next := n.NextSibling() + link.RemoveChild(link, n) + c.AppendChild(c, n) + n = next + } + + return c +} + +// AutoLinkType defines kind of auto links. +type AutoLinkType int + +const ( + // AutoLinkEmail indicates that an autolink is an email address. + AutoLinkEmail AutoLinkType = iota + 1 + // AutoLinkURL indicates that an autolink is a generic URL. + AutoLinkURL +) + +// An AutoLink struct represents an autolink of the Markdown text. +type AutoLink struct { + BaseInline + // Type is a type of this autolink. + AutoLinkType AutoLinkType + + // Protocol specified a protocol of the link. + Protocol []byte + + value *Text +} + +// Inline implements Inline.Inline. +func (n *AutoLink) Inline() {} + +// Dump implements Node.Dump +func (n *AutoLink) Dump(source []byte, level int) { + segment := n.value.Segment + m := map[string]string{ + "Value": string(segment.Value(source)), + } + DumpHelper(n, source, level, m, nil) +} + +// KindAutoLink is a NodeKind of the AutoLink node. +var KindAutoLink = NewNodeKind("AutoLink") + +// Kind implements Node.Kind. +func (n *AutoLink) Kind() NodeKind { + return KindAutoLink +} + +// URL returns an url of this node. +func (n *AutoLink) URL(source []byte) []byte { + if n.Protocol != nil { + s := n.value.Segment + ret := make([]byte, 0, len(n.Protocol)+s.Len()+3) + ret = append(ret, n.Protocol...) + ret = append(ret, ':', '/', '/') + ret = append(ret, n.value.Text(source)...) + return ret + } + return n.value.Text(source) +} + +// Label returns a label of this node. +func (n *AutoLink) Label(source []byte) []byte { + return n.value.Text(source) +} + +// NewAutoLink returns a new AutoLink node. +func NewAutoLink(typ AutoLinkType, value *Text) *AutoLink { + return &AutoLink{ + BaseInline: BaseInline{}, + value: value, + AutoLinkType: typ, + } +} + +// A RawHTML struct represents an inline raw HTML of the Markdown text. +type RawHTML struct { + BaseInline + Segments *textm.Segments +} + +// Inline implements Inline.Inline. +func (n *RawHTML) Inline() {} + +// Dump implements Node.Dump. +func (n *RawHTML) Dump(source []byte, level int) { + m := map[string]string{} + t := []string{} + for i := 0; i < n.Segments.Len(); i++ { + segment := n.Segments.At(i) + t = append(t, string(segment.Value(source))) + } + m["RawText"] = strings.Join(t, "") + DumpHelper(n, source, level, m, nil) +} + +// KindRawHTML is a NodeKind of the RawHTML node. +var KindRawHTML = NewNodeKind("RawHTML") + +// Kind implements Node.Kind. +func (n *RawHTML) Kind() NodeKind { + return KindRawHTML +} + +// NewRawHTML returns a new RawHTML node. +func NewRawHTML() *RawHTML { + return &RawHTML{ + Segments: textm.NewSegments(), + } +} diff --git a/vendor/github.com/yuin/goldmark/extension/ast/definition_list.go b/vendor/github.com/yuin/goldmark/extension/ast/definition_list.go new file mode 100644 index 0000000000..1beffb3aa4 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/ast/definition_list.go @@ -0,0 +1,83 @@ +package ast + +import ( + gast "github.com/yuin/goldmark/ast" +) + +// A DefinitionList struct represents a definition list of Markdown +// (PHPMarkdownExtra) text. +type DefinitionList struct { + gast.BaseBlock + Offset int + TemporaryParagraph *gast.Paragraph +} + +// Dump implements Node.Dump. +func (n *DefinitionList) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, nil) +} + +// KindDefinitionList is a NodeKind of the DefinitionList node. +var KindDefinitionList = gast.NewNodeKind("DefinitionList") + +// Kind implements Node.Kind. +func (n *DefinitionList) Kind() gast.NodeKind { + return KindDefinitionList +} + +// NewDefinitionList returns a new DefinitionList node. +func NewDefinitionList(offset int, para *gast.Paragraph) *DefinitionList { + return &DefinitionList{ + Offset: offset, + TemporaryParagraph: para, + } +} + +// A DefinitionTerm struct represents a definition list term of Markdown +// (PHPMarkdownExtra) text. +type DefinitionTerm struct { + gast.BaseBlock +} + +// Dump implements Node.Dump. +func (n *DefinitionTerm) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, nil) +} + +// KindDefinitionTerm is a NodeKind of the DefinitionTerm node. +var KindDefinitionTerm = gast.NewNodeKind("DefinitionTerm") + +// Kind implements Node.Kind. +func (n *DefinitionTerm) Kind() gast.NodeKind { + return KindDefinitionTerm +} + +// NewDefinitionTerm returns a new DefinitionTerm node. +func NewDefinitionTerm() *DefinitionTerm { + return &DefinitionTerm{} +} + +// A DefinitionDescription struct represents a definition list description of Markdown +// (PHPMarkdownExtra) text. +type DefinitionDescription struct { + gast.BaseBlock + IsTight bool +} + +// Dump implements Node.Dump. +func (n *DefinitionDescription) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, nil) +} + +// KindDefinitionDescription is a NodeKind of the DefinitionDescription node. +var KindDefinitionDescription = gast.NewNodeKind("DefinitionDescription") + +// Kind implements Node.Kind. +func (n *DefinitionDescription) Kind() gast.NodeKind { + return KindDefinitionDescription +} + +// NewDefinitionDescription returns a new DefinitionDescription node. +func NewDefinitionDescription() *DefinitionDescription { + return &DefinitionDescription{} +} diff --git a/vendor/github.com/yuin/goldmark/extension/ast/footnote.go b/vendor/github.com/yuin/goldmark/extension/ast/footnote.go new file mode 100644 index 0000000000..dedbab4f8b --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/ast/footnote.go @@ -0,0 +1,132 @@ +package ast + +import ( + "fmt" + + gast "github.com/yuin/goldmark/ast" +) + +// A FootnoteLink struct represents a link to a footnote of Markdown +// (PHP Markdown Extra) text. +type FootnoteLink struct { + gast.BaseInline + Index int + RefCount int +} + +// Dump implements Node.Dump. +func (n *FootnoteLink) Dump(source []byte, level int) { + m := map[string]string{} + m["Index"] = fmt.Sprintf("%v", n.Index) + m["RefCount"] = fmt.Sprintf("%v", n.RefCount) + gast.DumpHelper(n, source, level, m, nil) +} + +// KindFootnoteLink is a NodeKind of the FootnoteLink node. +var KindFootnoteLink = gast.NewNodeKind("FootnoteLink") + +// Kind implements Node.Kind. +func (n *FootnoteLink) Kind() gast.NodeKind { + return KindFootnoteLink +} + +// NewFootnoteLink returns a new FootnoteLink node. +func NewFootnoteLink(index int) *FootnoteLink { + return &FootnoteLink{ + Index: index, + RefCount: 0, + } +} + +// A FootnoteBacklink struct represents a link to a footnote of Markdown +// (PHP Markdown Extra) text. +type FootnoteBacklink struct { + gast.BaseInline + Index int + RefCount int +} + +// Dump implements Node.Dump. +func (n *FootnoteBacklink) Dump(source []byte, level int) { + m := map[string]string{} + m["Index"] = fmt.Sprintf("%v", n.Index) + m["RefCount"] = fmt.Sprintf("%v", n.RefCount) + gast.DumpHelper(n, source, level, m, nil) +} + +// KindFootnoteBacklink is a NodeKind of the FootnoteBacklink node. +var KindFootnoteBacklink = gast.NewNodeKind("FootnoteBacklink") + +// Kind implements Node.Kind. +func (n *FootnoteBacklink) Kind() gast.NodeKind { + return KindFootnoteBacklink +} + +// NewFootnoteBacklink returns a new FootnoteBacklink node. +func NewFootnoteBacklink(index int) *FootnoteBacklink { + return &FootnoteBacklink{ + Index: index, + RefCount: 0, + } +} + +// A Footnote struct represents a footnote of Markdown +// (PHP Markdown Extra) text. +type Footnote struct { + gast.BaseBlock + Ref []byte + Index int +} + +// Dump implements Node.Dump. +func (n *Footnote) Dump(source []byte, level int) { + m := map[string]string{} + m["Index"] = fmt.Sprintf("%v", n.Index) + m["Ref"] = fmt.Sprintf("%s", n.Ref) + gast.DumpHelper(n, source, level, m, nil) +} + +// KindFootnote is a NodeKind of the Footnote node. +var KindFootnote = gast.NewNodeKind("Footnote") + +// Kind implements Node.Kind. +func (n *Footnote) Kind() gast.NodeKind { + return KindFootnote +} + +// NewFootnote returns a new Footnote node. +func NewFootnote(ref []byte) *Footnote { + return &Footnote{ + Ref: ref, + Index: -1, + } +} + +// A FootnoteList struct represents footnotes of Markdown +// (PHP Markdown Extra) text. +type FootnoteList struct { + gast.BaseBlock + Count int +} + +// Dump implements Node.Dump. +func (n *FootnoteList) Dump(source []byte, level int) { + m := map[string]string{} + m["Count"] = fmt.Sprintf("%v", n.Count) + gast.DumpHelper(n, source, level, m, nil) +} + +// KindFootnoteList is a NodeKind of the FootnoteList node. +var KindFootnoteList = gast.NewNodeKind("FootnoteList") + +// Kind implements Node.Kind. +func (n *FootnoteList) Kind() gast.NodeKind { + return KindFootnoteList +} + +// NewFootnoteList returns a new FootnoteList node. +func NewFootnoteList() *FootnoteList { + return &FootnoteList{ + Count: 0, + } +} diff --git a/vendor/github.com/yuin/goldmark/extension/ast/strikethrough.go b/vendor/github.com/yuin/goldmark/extension/ast/strikethrough.go new file mode 100644 index 0000000000..a9216b72e8 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/ast/strikethrough.go @@ -0,0 +1,29 @@ +// Package ast defines AST nodes that represents extension's elements +package ast + +import ( + gast "github.com/yuin/goldmark/ast" +) + +// A Strikethrough struct represents a strikethrough of GFM text. +type Strikethrough struct { + gast.BaseInline +} + +// Dump implements Node.Dump. +func (n *Strikethrough) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, nil) +} + +// KindStrikethrough is a NodeKind of the Strikethrough node. +var KindStrikethrough = gast.NewNodeKind("Strikethrough") + +// Kind implements Node.Kind. +func (n *Strikethrough) Kind() gast.NodeKind { + return KindStrikethrough +} + +// NewStrikethrough returns a new Strikethrough node. +func NewStrikethrough() *Strikethrough { + return &Strikethrough{} +} diff --git a/vendor/github.com/yuin/goldmark/extension/ast/table.go b/vendor/github.com/yuin/goldmark/extension/ast/table.go new file mode 100644 index 0000000000..1d8890b5ef --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/ast/table.go @@ -0,0 +1,157 @@ +package ast + +import ( + "fmt" + gast "github.com/yuin/goldmark/ast" + "strings" +) + +// Alignment is a text alignment of table cells. +type Alignment int + +const ( + // AlignLeft indicates text should be left justified. + AlignLeft Alignment = iota + 1 + + // AlignRight indicates text should be right justified. + AlignRight + + // AlignCenter indicates text should be centered. + AlignCenter + + // AlignNone indicates text should be aligned by default manner. + AlignNone +) + +func (a Alignment) String() string { + switch a { + case AlignLeft: + return "left" + case AlignRight: + return "right" + case AlignCenter: + return "center" + case AlignNone: + return "none" + } + return "" +} + +// A Table struct represents a table of Markdown(GFM) text. +type Table struct { + gast.BaseBlock + + // Alignments returns alignments of the columns. + Alignments []Alignment +} + +// Dump implements Node.Dump +func (n *Table) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, func(level int) { + indent := strings.Repeat(" ", level) + fmt.Printf("%sAlignments {\n", indent) + for i, alignment := range n.Alignments { + indent2 := strings.Repeat(" ", level+1) + fmt.Printf("%s%s", indent2, alignment.String()) + if i != len(n.Alignments)-1 { + fmt.Println("") + } + } + fmt.Printf("\n%s}\n", indent) + }) +} + +// KindTable is a NodeKind of the Table node. +var KindTable = gast.NewNodeKind("Table") + +// Kind implements Node.Kind. +func (n *Table) Kind() gast.NodeKind { + return KindTable +} + +// NewTable returns a new Table node. +func NewTable() *Table { + return &Table{ + Alignments: []Alignment{}, + } +} + +// A TableRow struct represents a table row of Markdown(GFM) text. +type TableRow struct { + gast.BaseBlock + Alignments []Alignment +} + +// Dump implements Node.Dump. +func (n *TableRow) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, nil) +} + +// KindTableRow is a NodeKind of the TableRow node. +var KindTableRow = gast.NewNodeKind("TableRow") + +// Kind implements Node.Kind. +func (n *TableRow) Kind() gast.NodeKind { + return KindTableRow +} + +// NewTableRow returns a new TableRow node. +func NewTableRow(alignments []Alignment) *TableRow { + return &TableRow{} +} + +// A TableHeader struct represents a table header of Markdown(GFM) text. +type TableHeader struct { + gast.BaseBlock + Alignments []Alignment +} + +// KindTableHeader is a NodeKind of the TableHeader node. +var KindTableHeader = gast.NewNodeKind("TableHeader") + +// Kind implements Node.Kind. +func (n *TableHeader) Kind() gast.NodeKind { + return KindTableHeader +} + +// Dump implements Node.Dump. +func (n *TableHeader) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, nil) +} + +// NewTableHeader returns a new TableHeader node. +func NewTableHeader(row *TableRow) *TableHeader { + n := &TableHeader{} + for c := row.FirstChild(); c != nil; { + next := c.NextSibling() + n.AppendChild(n, c) + c = next + } + return n +} + +// A TableCell struct represents a table cell of a Markdown(GFM) text. +type TableCell struct { + gast.BaseBlock + Alignment Alignment +} + +// Dump implements Node.Dump. +func (n *TableCell) Dump(source []byte, level int) { + gast.DumpHelper(n, source, level, nil, nil) +} + +// KindTableCell is a NodeKind of the TableCell node. +var KindTableCell = gast.NewNodeKind("TableCell") + +// Kind implements Node.Kind. +func (n *TableCell) Kind() gast.NodeKind { + return KindTableCell +} + +// NewTableCell returns a new TableCell node. +func NewTableCell() *TableCell { + return &TableCell{ + Alignment: AlignNone, + } +} diff --git a/vendor/github.com/yuin/goldmark/extension/ast/tasklist.go b/vendor/github.com/yuin/goldmark/extension/ast/tasklist.go new file mode 100644 index 0000000000..670cc14952 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/ast/tasklist.go @@ -0,0 +1,35 @@ +package ast + +import ( + "fmt" + gast "github.com/yuin/goldmark/ast" +) + +// A TaskCheckBox struct represents a checkbox of a task list. +type TaskCheckBox struct { + gast.BaseInline + IsChecked bool +} + +// Dump implements Node.Dump. +func (n *TaskCheckBox) Dump(source []byte, level int) { + m := map[string]string{ + "Checked": fmt.Sprintf("%v", n.IsChecked), + } + gast.DumpHelper(n, source, level, m, nil) +} + +// KindTaskCheckBox is a NodeKind of the TaskCheckBox node. +var KindTaskCheckBox = gast.NewNodeKind("TaskCheckBox") + +// Kind implements Node.Kind. +func (n *TaskCheckBox) Kind() gast.NodeKind { + return KindTaskCheckBox +} + +// NewTaskCheckBox returns a new TaskCheckBox node. +func NewTaskCheckBox(checked bool) *TaskCheckBox { + return &TaskCheckBox{ + IsChecked: checked, + } +} diff --git a/vendor/github.com/yuin/goldmark/extension/definition_list.go b/vendor/github.com/yuin/goldmark/extension/definition_list.go new file mode 100644 index 0000000000..d2f5fecbe0 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/definition_list.go @@ -0,0 +1,270 @@ +package extension + +import ( + "github.com/yuin/goldmark" + gast "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type definitionListParser struct { +} + +var defaultDefinitionListParser = &definitionListParser{} + +// NewDefinitionListParser return a new parser.BlockParser that +// can parse PHP Markdown Extra Definition lists. +func NewDefinitionListParser() parser.BlockParser { + return defaultDefinitionListParser +} + +func (b *definitionListParser) Trigger() []byte { + return []byte{':'} +} + +func (b *definitionListParser) Open(parent gast.Node, reader text.Reader, pc parser.Context) (gast.Node, parser.State) { + if _, ok := parent.(*ast.DefinitionList); ok { + return nil, parser.NoChildren + } + line, _ := reader.PeekLine() + pos := pc.BlockOffset() + indent := pc.BlockIndent() + if pos < 0 || line[pos] != ':' || indent != 0 { + return nil, parser.NoChildren + } + + last := parent.LastChild() + // need 1 or more spaces after ':' + w, _ := util.IndentWidth(line[pos+1:], pos+1) + if w < 1 { + return nil, parser.NoChildren + } + if w >= 8 { // starts with indented code + w = 5 + } + w += pos + 1 /* 1 = ':' */ + + para, lastIsParagraph := last.(*gast.Paragraph) + var list *ast.DefinitionList + status := parser.HasChildren + var ok bool + if lastIsParagraph { + list, ok = last.PreviousSibling().(*ast.DefinitionList) + if ok { // is not first item + list.Offset = w + list.TemporaryParagraph = para + } else { // is first item + list = ast.NewDefinitionList(w, para) + status |= parser.RequireParagraph + } + } else if list, ok = last.(*ast.DefinitionList); ok { // multiple description + list.Offset = w + list.TemporaryParagraph = nil + } else { + return nil, parser.NoChildren + } + + return list, status +} + +func (b *definitionListParser) Continue(node gast.Node, reader text.Reader, pc parser.Context) parser.State { + line, _ := reader.PeekLine() + if util.IsBlank(line) { + return parser.Continue | parser.HasChildren + } + list, _ := node.(*ast.DefinitionList) + w, _ := util.IndentWidth(line, reader.LineOffset()) + if w < list.Offset { + return parser.Close + } + pos, padding := util.IndentPosition(line, reader.LineOffset(), list.Offset) + reader.AdvanceAndSetPadding(pos, padding) + return parser.Continue | parser.HasChildren +} + +func (b *definitionListParser) Close(node gast.Node, reader text.Reader, pc parser.Context) { + // nothing to do +} + +func (b *definitionListParser) CanInterruptParagraph() bool { + return true +} + +func (b *definitionListParser) CanAcceptIndentedLine() bool { + return false +} + +type definitionDescriptionParser struct { +} + +var defaultDefinitionDescriptionParser = &definitionDescriptionParser{} + +// NewDefinitionDescriptionParser return a new parser.BlockParser that +// can parse definition description starts with ':'. +func NewDefinitionDescriptionParser() parser.BlockParser { + return defaultDefinitionDescriptionParser +} + +func (b *definitionDescriptionParser) Trigger() []byte { + return []byte{':'} +} + +func (b *definitionDescriptionParser) Open(parent gast.Node, reader text.Reader, pc parser.Context) (gast.Node, parser.State) { + line, _ := reader.PeekLine() + pos := pc.BlockOffset() + indent := pc.BlockIndent() + if pos < 0 || line[pos] != ':' || indent != 0 { + return nil, parser.NoChildren + } + list, _ := parent.(*ast.DefinitionList) + if list == nil { + return nil, parser.NoChildren + } + para := list.TemporaryParagraph + list.TemporaryParagraph = nil + if para != nil { + lines := para.Lines() + l := lines.Len() + for i := 0; i < l; i++ { + term := ast.NewDefinitionTerm() + segment := lines.At(i) + term.Lines().Append(segment.TrimRightSpace(reader.Source())) + list.AppendChild(list, term) + } + para.Parent().RemoveChild(para.Parent(), para) + } + cpos, padding := util.IndentPosition(line[pos+1:], pos+1, list.Offset-pos-1) + reader.AdvanceAndSetPadding(cpos+1, padding) + + return ast.NewDefinitionDescription(), parser.HasChildren +} + +func (b *definitionDescriptionParser) Continue(node gast.Node, reader text.Reader, pc parser.Context) parser.State { + // definitionListParser detects end of the description. + // so this method will never be called. + return parser.Continue | parser.HasChildren +} + +func (b *definitionDescriptionParser) Close(node gast.Node, reader text.Reader, pc parser.Context) { + desc := node.(*ast.DefinitionDescription) + desc.IsTight = !desc.HasBlankPreviousLines() + if desc.IsTight { + for gc := desc.FirstChild(); gc != nil; gc = gc.NextSibling() { + paragraph, ok := gc.(*gast.Paragraph) + if ok { + textBlock := gast.NewTextBlock() + textBlock.SetLines(paragraph.Lines()) + desc.ReplaceChild(desc, paragraph, textBlock) + } + } + } +} + +func (b *definitionDescriptionParser) CanInterruptParagraph() bool { + return true +} + +func (b *definitionDescriptionParser) CanAcceptIndentedLine() bool { + return false +} + +// DefinitionListHTMLRenderer is a renderer.NodeRenderer implementation that +// renders DefinitionList nodes. +type DefinitionListHTMLRenderer struct { + html.Config +} + +// NewDefinitionListHTMLRenderer returns a new DefinitionListHTMLRenderer. +func NewDefinitionListHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { + r := &DefinitionListHTMLRenderer{ + Config: html.NewConfig(), + } + for _, opt := range opts { + opt.SetHTMLOption(&r.Config) + } + return r +} + +// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. +func (r *DefinitionListHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(ast.KindDefinitionList, r.renderDefinitionList) + reg.Register(ast.KindDefinitionTerm, r.renderDefinitionTerm) + reg.Register(ast.KindDefinitionDescription, r.renderDefinitionDescription) +} + +// DefinitionListAttributeFilter defines attribute names which dl elements can have. +var DefinitionListAttributeFilter = html.GlobalAttributeFilter + +func (r *DefinitionListHTMLRenderer) renderDefinitionList(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("\n") + } else { + _, _ = w.WriteString("
\n") + } + } else { + _, _ = w.WriteString("
\n") + } + return gast.WalkContinue, nil +} + +// DefinitionTermAttributeFilter defines attribute names which dd elements can have. +var DefinitionTermAttributeFilter = html.GlobalAttributeFilter + +func (r *DefinitionListHTMLRenderer) renderDefinitionTerm(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("
") + } + } else { + _, _ = w.WriteString("
\n") + } + return gast.WalkContinue, nil +} + +// DefinitionDescriptionAttributeFilter defines attribute names which dd elements can have. +var DefinitionDescriptionAttributeFilter = html.GlobalAttributeFilter + +func (r *DefinitionListHTMLRenderer) renderDefinitionDescription(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + n := node.(*ast.DefinitionDescription) + _, _ = w.WriteString("") + } else { + _, _ = w.WriteString(">\n") + } + } else { + _, _ = w.WriteString("\n") + } + return gast.WalkContinue, nil +} + +type definitionList struct { +} + +// DefinitionList is an extension that allow you to use PHP Markdown Extra Definition lists. +var DefinitionList = &definitionList{} + +func (e *definitionList) Extend(m goldmark.Markdown) { + m.Parser().AddOptions(parser.WithBlockParsers( + util.Prioritized(NewDefinitionListParser(), 101), + util.Prioritized(NewDefinitionDescriptionParser(), 102), + )) + m.Renderer().AddOptions(renderer.WithNodeRenderers( + util.Prioritized(NewDefinitionListHTMLRenderer(), 500), + )) +} diff --git a/vendor/github.com/yuin/goldmark/extension/footnote.go b/vendor/github.com/yuin/goldmark/extension/footnote.go new file mode 100644 index 0000000000..d4552e5a4a --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/footnote.go @@ -0,0 +1,670 @@ +package extension + +import ( + "bytes" + "strconv" + + "github.com/yuin/goldmark" + gast "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var footnoteListKey = parser.NewContextKey() +var footnoteLinkListKey = parser.NewContextKey() + +type footnoteBlockParser struct { +} + +var defaultFootnoteBlockParser = &footnoteBlockParser{} + +// NewFootnoteBlockParser returns a new parser.BlockParser that can parse +// footnotes of the Markdown(PHP Markdown Extra) text. +func NewFootnoteBlockParser() parser.BlockParser { + return defaultFootnoteBlockParser +} + +func (b *footnoteBlockParser) Trigger() []byte { + return []byte{'['} +} + +func (b *footnoteBlockParser) Open(parent gast.Node, reader text.Reader, pc parser.Context) (gast.Node, parser.State) { + line, segment := reader.PeekLine() + pos := pc.BlockOffset() + if pos < 0 || line[pos] != '[' { + return nil, parser.NoChildren + } + pos++ + if pos > len(line)-1 || line[pos] != '^' { + return nil, parser.NoChildren + } + open := pos + 1 + closes := 0 + closure := util.FindClosure(line[pos+1:], '[', ']', false, false) + closes = pos + 1 + closure + next := closes + 1 + if closure > -1 { + if next >= len(line) || line[next] != ':' { + return nil, parser.NoChildren + } + } else { + return nil, parser.NoChildren + } + padding := segment.Padding + label := reader.Value(text.NewSegment(segment.Start+open-padding, segment.Start+closes-padding)) + if util.IsBlank(label) { + return nil, parser.NoChildren + } + item := ast.NewFootnote(label) + + pos = next + 1 - padding + if pos >= len(line) { + reader.Advance(pos) + return item, parser.NoChildren + } + reader.AdvanceAndSetPadding(pos, padding) + return item, parser.HasChildren +} + +func (b *footnoteBlockParser) Continue(node gast.Node, reader text.Reader, pc parser.Context) parser.State { + line, _ := reader.PeekLine() + if util.IsBlank(line) { + return parser.Continue | parser.HasChildren + } + childpos, padding := util.IndentPosition(line, reader.LineOffset(), 4) + if childpos < 0 { + return parser.Close + } + reader.AdvanceAndSetPadding(childpos, padding) + return parser.Continue | parser.HasChildren +} + +func (b *footnoteBlockParser) Close(node gast.Node, reader text.Reader, pc parser.Context) { + var list *ast.FootnoteList + if tlist := pc.Get(footnoteListKey); tlist != nil { + list = tlist.(*ast.FootnoteList) + } else { + list = ast.NewFootnoteList() + pc.Set(footnoteListKey, list) + node.Parent().InsertBefore(node.Parent(), node, list) + } + node.Parent().RemoveChild(node.Parent(), node) + list.AppendChild(list, node) +} + +func (b *footnoteBlockParser) CanInterruptParagraph() bool { + return true +} + +func (b *footnoteBlockParser) CanAcceptIndentedLine() bool { + return false +} + +type footnoteParser struct { +} + +var defaultFootnoteParser = &footnoteParser{} + +// NewFootnoteParser returns a new parser.InlineParser that can parse +// footnote links of the Markdown(PHP Markdown Extra) text. +func NewFootnoteParser() parser.InlineParser { + return defaultFootnoteParser +} + +func (s *footnoteParser) Trigger() []byte { + // footnote syntax probably conflict with the image syntax. + // So we need trigger this parser with '!'. + return []byte{'!', '['} +} + +func (s *footnoteParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { + line, segment := block.PeekLine() + pos := 1 + if len(line) > 0 && line[0] == '!' { + pos++ + } + if pos >= len(line) || line[pos] != '^' { + return nil + } + pos++ + if pos >= len(line) { + return nil + } + open := pos + closure := util.FindClosure(line[pos:], '[', ']', false, false) + if closure < 0 { + return nil + } + closes := pos + closure + value := block.Value(text.NewSegment(segment.Start+open, segment.Start+closes)) + block.Advance(closes + 1) + + var list *ast.FootnoteList + if tlist := pc.Get(footnoteListKey); tlist != nil { + list = tlist.(*ast.FootnoteList) + } + if list == nil { + return nil + } + index := 0 + for def := list.FirstChild(); def != nil; def = def.NextSibling() { + d := def.(*ast.Footnote) + if bytes.Equal(d.Ref, value) { + if d.Index < 0 { + list.Count += 1 + d.Index = list.Count + } + index = d.Index + break + } + } + if index == 0 { + return nil + } + + fnlink := ast.NewFootnoteLink(index) + var fnlist []*ast.FootnoteLink + if tmp := pc.Get(footnoteLinkListKey); tmp != nil { + fnlist = tmp.([]*ast.FootnoteLink) + } else { + fnlist = []*ast.FootnoteLink{} + pc.Set(footnoteLinkListKey, fnlist) + } + pc.Set(footnoteLinkListKey, append(fnlist, fnlink)) + if line[0] == '!' { + parent.AppendChild(parent, gast.NewTextSegment(text.NewSegment(segment.Start, segment.Start+1))) + } + + return fnlink +} + +type footnoteASTTransformer struct { +} + +var defaultFootnoteASTTransformer = &footnoteASTTransformer{} + +// NewFootnoteASTTransformer returns a new parser.ASTTransformer that +// insert a footnote list to the last of the document. +func NewFootnoteASTTransformer() parser.ASTTransformer { + return defaultFootnoteASTTransformer +} + +func (a *footnoteASTTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) { + var list *ast.FootnoteList + var fnlist []*ast.FootnoteLink + if tmp := pc.Get(footnoteListKey); tmp != nil { + list = tmp.(*ast.FootnoteList) + } + if tmp := pc.Get(footnoteLinkListKey); tmp != nil { + fnlist = tmp.([]*ast.FootnoteLink) + } + + pc.Set(footnoteListKey, nil) + pc.Set(footnoteLinkListKey, nil) + + if list == nil { + return + } + + counter := map[int]int{} + if fnlist != nil { + for _, fnlink := range fnlist { + if fnlink.Index >= 0 { + counter[fnlink.Index]++ + } + } + for _, fnlink := range fnlist { + fnlink.RefCount = counter[fnlink.Index] + } + } + for footnote := list.FirstChild(); footnote != nil; { + var container gast.Node = footnote + next := footnote.NextSibling() + if fc := container.LastChild(); fc != nil && gast.IsParagraph(fc) { + container = fc + } + fn := footnote.(*ast.Footnote) + index := fn.Index + if index < 0 { + list.RemoveChild(list, footnote) + } else { + backLink := ast.NewFootnoteBacklink(index) + backLink.RefCount = counter[index] + container.AppendChild(container, backLink) + } + footnote = next + } + list.SortChildren(func(n1, n2 gast.Node) int { + if n1.(*ast.Footnote).Index < n2.(*ast.Footnote).Index { + return -1 + } + return 1 + }) + if list.Count <= 0 { + list.Parent().RemoveChild(list.Parent(), list) + return + } + + node.AppendChild(node, list) +} + +// FootnoteConfig holds configuration values for the footnote extension. +// +// Link* and Backlink* configurations have some variables: +// Occurrances of “^^” in the string will be replaced by the +// corresponding footnote number in the HTML output. +// Occurrances of “%%” will be replaced by a number for the +// reference (footnotes can have multiple references). +type FootnoteConfig struct { + html.Config + + // IDPrefix is a prefix for the id attributes generated by footnotes. + IDPrefix []byte + + // IDPrefix is a function that determines the id attribute for given Node. + IDPrefixFunction func(gast.Node) []byte + + // LinkTitle is an optional title attribute for footnote links. + LinkTitle []byte + + // BacklinkTitle is an optional title attribute for footnote backlinks. + BacklinkTitle []byte + + // LinkClass is a class for footnote links. + LinkClass []byte + + // BacklinkClass is a class for footnote backlinks. + BacklinkClass []byte + + // BacklinkHTML is an HTML content for footnote backlinks. + BacklinkHTML []byte +} + +// FootnoteOption interface is a functional option interface for the extension. +type FootnoteOption interface { + renderer.Option + // SetFootnoteOption sets given option to the extension. + SetFootnoteOption(*FootnoteConfig) +} + +// NewFootnoteConfig returns a new Config with defaults. +func NewFootnoteConfig() FootnoteConfig { + return FootnoteConfig{ + Config: html.NewConfig(), + LinkTitle: []byte(""), + BacklinkTitle: []byte(""), + LinkClass: []byte("footnote-ref"), + BacklinkClass: []byte("footnote-backref"), + BacklinkHTML: []byte("↩︎"), + } +} + +// SetOption implements renderer.SetOptioner. +func (c *FootnoteConfig) SetOption(name renderer.OptionName, value interface{}) { + switch name { + case optFootnoteIDPrefixFunction: + c.IDPrefixFunction = value.(func(gast.Node) []byte) + case optFootnoteIDPrefix: + c.IDPrefix = value.([]byte) + case optFootnoteLinkTitle: + c.LinkTitle = value.([]byte) + case optFootnoteBacklinkTitle: + c.BacklinkTitle = value.([]byte) + case optFootnoteLinkClass: + c.LinkClass = value.([]byte) + case optFootnoteBacklinkClass: + c.BacklinkClass = value.([]byte) + case optFootnoteBacklinkHTML: + c.BacklinkHTML = value.([]byte) + default: + c.Config.SetOption(name, value) + } +} + +type withFootnoteHTMLOptions struct { + value []html.Option +} + +func (o *withFootnoteHTMLOptions) SetConfig(c *renderer.Config) { + if o.value != nil { + for _, v := range o.value { + v.(renderer.Option).SetConfig(c) + } + } +} + +func (o *withFootnoteHTMLOptions) SetFootnoteOption(c *FootnoteConfig) { + if o.value != nil { + for _, v := range o.value { + v.SetHTMLOption(&c.Config) + } + } +} + +// WithFootnoteHTMLOptions is functional option that wraps goldmark HTMLRenderer options. +func WithFootnoteHTMLOptions(opts ...html.Option) FootnoteOption { + return &withFootnoteHTMLOptions{opts} +} + +const optFootnoteIDPrefix renderer.OptionName = "FootnoteIDPrefix" + +type withFootnoteIDPrefix struct { + value []byte +} + +func (o *withFootnoteIDPrefix) SetConfig(c *renderer.Config) { + c.Options[optFootnoteIDPrefix] = o.value +} + +func (o *withFootnoteIDPrefix) SetFootnoteOption(c *FootnoteConfig) { + c.IDPrefix = o.value +} + +// WithFootnoteIDPrefix is a functional option that is a prefix for the id attributes generated by footnotes. +func WithFootnoteIDPrefix(a []byte) FootnoteOption { + return &withFootnoteIDPrefix{a} +} + +const optFootnoteIDPrefixFunction renderer.OptionName = "FootnoteIDPrefixFunction" + +type withFootnoteIDPrefixFunction struct { + value func(gast.Node) []byte +} + +func (o *withFootnoteIDPrefixFunction) SetConfig(c *renderer.Config) { + c.Options[optFootnoteIDPrefixFunction] = o.value +} + +func (o *withFootnoteIDPrefixFunction) SetFootnoteOption(c *FootnoteConfig) { + c.IDPrefixFunction = o.value +} + +// WithFootnoteIDPrefixFunction is a functional option that is a prefix for the id attributes generated by footnotes. +func WithFootnoteIDPrefixFunction(a func(gast.Node) []byte) FootnoteOption { + return &withFootnoteIDPrefixFunction{a} +} + +const optFootnoteLinkTitle renderer.OptionName = "FootnoteLinkTitle" + +type withFootnoteLinkTitle struct { + value []byte +} + +func (o *withFootnoteLinkTitle) SetConfig(c *renderer.Config) { + c.Options[optFootnoteLinkTitle] = o.value +} + +func (o *withFootnoteLinkTitle) SetFootnoteOption(c *FootnoteConfig) { + c.LinkTitle = o.value +} + +// WithFootnoteLinkTitle is a functional option that is an optional title attribute for footnote links. +func WithFootnoteLinkTitle(a []byte) FootnoteOption { + return &withFootnoteLinkTitle{a} +} + +const optFootnoteBacklinkTitle renderer.OptionName = "FootnoteBacklinkTitle" + +type withFootnoteBacklinkTitle struct { + value []byte +} + +func (o *withFootnoteBacklinkTitle) SetConfig(c *renderer.Config) { + c.Options[optFootnoteBacklinkTitle] = o.value +} + +func (o *withFootnoteBacklinkTitle) SetFootnoteOption(c *FootnoteConfig) { + c.BacklinkTitle = o.value +} + +// WithFootnoteBacklinkTitle is a functional option that is an optional title attribute for footnote backlinks. +func WithFootnoteBacklinkTitle(a []byte) FootnoteOption { + return &withFootnoteBacklinkTitle{a} +} + +const optFootnoteLinkClass renderer.OptionName = "FootnoteLinkClass" + +type withFootnoteLinkClass struct { + value []byte +} + +func (o *withFootnoteLinkClass) SetConfig(c *renderer.Config) { + c.Options[optFootnoteLinkClass] = o.value +} + +func (o *withFootnoteLinkClass) SetFootnoteOption(c *FootnoteConfig) { + c.LinkClass = o.value +} + +// WithFootnoteLinkClass is a functional option that is a class for footnote links. +func WithFootnoteLinkClass(a []byte) FootnoteOption { + return &withFootnoteLinkClass{a} +} + +const optFootnoteBacklinkClass renderer.OptionName = "FootnoteBacklinkClass" + +type withFootnoteBacklinkClass struct { + value []byte +} + +func (o *withFootnoteBacklinkClass) SetConfig(c *renderer.Config) { + c.Options[optFootnoteBacklinkClass] = o.value +} + +func (o *withFootnoteBacklinkClass) SetFootnoteOption(c *FootnoteConfig) { + c.BacklinkClass = o.value +} + +// WithFootnoteBacklinkClass is a functional option that is a class for footnote backlinks. +func WithFootnoteBacklinkClass(a []byte) FootnoteOption { + return &withFootnoteBacklinkClass{a} +} + +const optFootnoteBacklinkHTML renderer.OptionName = "FootnoteBacklinkHTML" + +type withFootnoteBacklinkHTML struct { + value []byte +} + +func (o *withFootnoteBacklinkHTML) SetConfig(c *renderer.Config) { + c.Options[optFootnoteBacklinkHTML] = o.value +} + +func (o *withFootnoteBacklinkHTML) SetFootnoteOption(c *FootnoteConfig) { + c.BacklinkHTML = o.value +} + +// WithFootnoteBacklinkHTML is an HTML content for footnote backlinks. +func WithFootnoteBacklinkHTML(a []byte) FootnoteOption { + return &withFootnoteBacklinkHTML{a} +} + +// FootnoteHTMLRenderer is a renderer.NodeRenderer implementation that +// renders FootnoteLink nodes. +type FootnoteHTMLRenderer struct { + FootnoteConfig +} + +// NewFootnoteHTMLRenderer returns a new FootnoteHTMLRenderer. +func NewFootnoteHTMLRenderer(opts ...FootnoteOption) renderer.NodeRenderer { + r := &FootnoteHTMLRenderer{ + FootnoteConfig: NewFootnoteConfig(), + } + for _, opt := range opts { + opt.SetFootnoteOption(&r.FootnoteConfig) + } + return r +} + +// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. +func (r *FootnoteHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(ast.KindFootnoteLink, r.renderFootnoteLink) + reg.Register(ast.KindFootnoteBacklink, r.renderFootnoteBacklink) + reg.Register(ast.KindFootnote, r.renderFootnote) + reg.Register(ast.KindFootnoteList, r.renderFootnoteList) +} + +func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + n := node.(*ast.FootnoteLink) + is := strconv.Itoa(n.Index) + _, _ = w.WriteString(``) + + _, _ = w.WriteString(is) + _, _ = w.WriteString(``) + } + return gast.WalkContinue, nil +} + +func (r *FootnoteHTMLRenderer) renderFootnoteBacklink(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + n := node.(*ast.FootnoteBacklink) + is := strconv.Itoa(n.Index) + _, _ = w.WriteString(` `) + _, _ = w.Write(applyFootnoteTemplate(r.FootnoteConfig.BacklinkHTML, n.Index, n.RefCount)) + _, _ = w.WriteString(``) + } + return gast.WalkContinue, nil +} + +func (r *FootnoteHTMLRenderer) renderFootnote(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { + n := node.(*ast.Footnote) + is := strconv.Itoa(n.Index) + if entering { + _, _ = w.WriteString(`
  • \n") + } else { + _, _ = w.WriteString("
  • \n") + } + return gast.WalkContinue, nil +} + +func (r *FootnoteHTMLRenderer) renderFootnoteList(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { + tag := "section" + if r.Config.XHTML { + tag = "div" + } + if entering { + _, _ = w.WriteString("<") + _, _ = w.WriteString(tag) + _, _ = w.WriteString(` class="footnotes" role="doc-endnotes"`) + if node.Attributes() != nil { + html.RenderAttributes(w, node, html.GlobalAttributeFilter) + } + _ = w.WriteByte('>') + if r.Config.XHTML { + _, _ = w.WriteString("\n
    \n") + } else { + _, _ = w.WriteString("\n
    \n") + } + _, _ = w.WriteString("
      \n") + } else { + _, _ = w.WriteString("
    \n") + _, _ = w.WriteString("\n") + } + return gast.WalkContinue, nil +} + +func (r *FootnoteHTMLRenderer) idPrefix(node gast.Node) []byte { + if r.FootnoteConfig.IDPrefix != nil { + return r.FootnoteConfig.IDPrefix + } + if r.FootnoteConfig.IDPrefixFunction != nil { + return r.FootnoteConfig.IDPrefixFunction(node) + } + return []byte("") +} + +func applyFootnoteTemplate(b []byte, index, refCount int) []byte { + fast := true + for i, c := range b { + if i != 0 { + if b[i-1] == '^' && c == '^' { + fast = false + break + } + if b[i-1] == '%' && c == '%' { + fast = false + break + } + } + } + if fast { + return b + } + is := []byte(strconv.Itoa(index)) + rs := []byte(strconv.Itoa(refCount)) + ret := bytes.Replace(b, []byte("^^"), is, -1) + return bytes.Replace(ret, []byte("%%"), rs, -1) +} + +type footnote struct { + options []FootnoteOption +} + +// Footnote is an extension that allow you to use PHP Markdown Extra Footnotes. +var Footnote = &footnote{ + options: []FootnoteOption{}, +} + +// NewFootnote returns a new extension with given options. +func NewFootnote(opts ...FootnoteOption) goldmark.Extender { + return &footnote{ + options: opts, + } +} + +func (e *footnote) Extend(m goldmark.Markdown) { + m.Parser().AddOptions( + parser.WithBlockParsers( + util.Prioritized(NewFootnoteBlockParser(), 999), + ), + parser.WithInlineParsers( + util.Prioritized(NewFootnoteParser(), 101), + ), + parser.WithASTTransformers( + util.Prioritized(NewFootnoteASTTransformer(), 999), + ), + ) + m.Renderer().AddOptions(renderer.WithNodeRenderers( + util.Prioritized(NewFootnoteHTMLRenderer(e.options...), 500), + )) +} diff --git a/vendor/github.com/yuin/goldmark/extension/gfm.go b/vendor/github.com/yuin/goldmark/extension/gfm.go new file mode 100644 index 0000000000..a570fbdb36 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/gfm.go @@ -0,0 +1,18 @@ +package extension + +import ( + "github.com/yuin/goldmark" +) + +type gfm struct { +} + +// GFM is an extension that provides Github Flavored markdown functionalities. +var GFM = &gfm{} + +func (e *gfm) Extend(m goldmark.Markdown) { + Linkify.Extend(m) + Table.Extend(m) + Strikethrough.Extend(m) + TaskList.Extend(m) +} diff --git a/vendor/github.com/yuin/goldmark/extension/linkify.go b/vendor/github.com/yuin/goldmark/extension/linkify.go new file mode 100644 index 0000000000..42a87c8e6e --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/linkify.go @@ -0,0 +1,307 @@ +package extension + +import ( + "bytes" + "regexp" + + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?:[/#?][-a-zA-Z0-9@:%_\+.~#!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`) + +var urlRegexp = regexp.MustCompile(`^(?:http|https|ftp)://[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?::\d+)?(?:[/#?][-a-zA-Z0-9@:%_+.~#$!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`) + +// An LinkifyConfig struct is a data structure that holds configuration of the +// Linkify extension. +type LinkifyConfig struct { + AllowedProtocols [][]byte + URLRegexp *regexp.Regexp + WWWRegexp *regexp.Regexp + EmailRegexp *regexp.Regexp +} + +const ( + optLinkifyAllowedProtocols parser.OptionName = "LinkifyAllowedProtocols" + optLinkifyURLRegexp parser.OptionName = "LinkifyURLRegexp" + optLinkifyWWWRegexp parser.OptionName = "LinkifyWWWRegexp" + optLinkifyEmailRegexp parser.OptionName = "LinkifyEmailRegexp" +) + +// SetOption implements SetOptioner. +func (c *LinkifyConfig) SetOption(name parser.OptionName, value interface{}) { + switch name { + case optLinkifyAllowedProtocols: + c.AllowedProtocols = value.([][]byte) + case optLinkifyURLRegexp: + c.URLRegexp = value.(*regexp.Regexp) + case optLinkifyWWWRegexp: + c.WWWRegexp = value.(*regexp.Regexp) + case optLinkifyEmailRegexp: + c.EmailRegexp = value.(*regexp.Regexp) + } +} + +// A LinkifyOption interface sets options for the LinkifyOption. +type LinkifyOption interface { + parser.Option + SetLinkifyOption(*LinkifyConfig) +} + +type withLinkifyAllowedProtocols struct { + value [][]byte +} + +func (o *withLinkifyAllowedProtocols) SetParserOption(c *parser.Config) { + c.Options[optLinkifyAllowedProtocols] = o.value +} + +func (o *withLinkifyAllowedProtocols) SetLinkifyOption(p *LinkifyConfig) { + p.AllowedProtocols = o.value +} + +// WithLinkifyAllowedProtocols is a functional option that specify allowed +// protocols in autolinks. Each protocol must end with ':' like +// 'http:' . +func WithLinkifyAllowedProtocols(value [][]byte) LinkifyOption { + return &withLinkifyAllowedProtocols{ + value: value, + } +} + +type withLinkifyURLRegexp struct { + value *regexp.Regexp +} + +func (o *withLinkifyURLRegexp) SetParserOption(c *parser.Config) { + c.Options[optLinkifyURLRegexp] = o.value +} + +func (o *withLinkifyURLRegexp) SetLinkifyOption(p *LinkifyConfig) { + p.URLRegexp = o.value +} + +// WithLinkifyURLRegexp is a functional option that specify +// a pattern of the URL including a protocol. +func WithLinkifyURLRegexp(value *regexp.Regexp) LinkifyOption { + return &withLinkifyURLRegexp{ + value: value, + } +} + +// WithLinkifyWWWRegexp is a functional option that specify +// a pattern of the URL without a protocol. +// This pattern must start with 'www.' . +type withLinkifyWWWRegexp struct { + value *regexp.Regexp +} + +func (o *withLinkifyWWWRegexp) SetParserOption(c *parser.Config) { + c.Options[optLinkifyWWWRegexp] = o.value +} + +func (o *withLinkifyWWWRegexp) SetLinkifyOption(p *LinkifyConfig) { + p.WWWRegexp = o.value +} + +func WithLinkifyWWWRegexp(value *regexp.Regexp) LinkifyOption { + return &withLinkifyWWWRegexp{ + value: value, + } +} + +// WithLinkifyWWWRegexp is a functional otpion that specify +// a pattern of the email address. +type withLinkifyEmailRegexp struct { + value *regexp.Regexp +} + +func (o *withLinkifyEmailRegexp) SetParserOption(c *parser.Config) { + c.Options[optLinkifyEmailRegexp] = o.value +} + +func (o *withLinkifyEmailRegexp) SetLinkifyOption(p *LinkifyConfig) { + p.EmailRegexp = o.value +} + +func WithLinkifyEmailRegexp(value *regexp.Regexp) LinkifyOption { + return &withLinkifyEmailRegexp{ + value: value, + } +} + +type linkifyParser struct { + LinkifyConfig +} + +// NewLinkifyParser return a new InlineParser can parse +// text that seems like a URL. +func NewLinkifyParser(opts ...LinkifyOption) parser.InlineParser { + p := &linkifyParser{ + LinkifyConfig: LinkifyConfig{ + AllowedProtocols: nil, + URLRegexp: urlRegexp, + WWWRegexp: wwwURLRegxp, + }, + } + for _, o := range opts { + o.SetLinkifyOption(&p.LinkifyConfig) + } + return p +} + +func (s *linkifyParser) Trigger() []byte { + // ' ' indicates any white spaces and a line head + return []byte{' ', '*', '_', '~', '('} +} + +var ( + protoHTTP = []byte("http:") + protoHTTPS = []byte("https:") + protoFTP = []byte("ftp:") + domainWWW = []byte("www.") +) + +func (s *linkifyParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node { + if pc.IsInLinkLabel() { + return nil + } + line, segment := block.PeekLine() + consumes := 0 + start := segment.Start + c := line[0] + // advance if current position is not a line head. + if c == ' ' || c == '*' || c == '_' || c == '~' || c == '(' { + consumes++ + start++ + line = line[1:] + } + + var m []int + var protocol []byte + var typ ast.AutoLinkType = ast.AutoLinkURL + if s.LinkifyConfig.AllowedProtocols == nil { + if bytes.HasPrefix(line, protoHTTP) || bytes.HasPrefix(line, protoHTTPS) || bytes.HasPrefix(line, protoFTP) { + m = s.LinkifyConfig.URLRegexp.FindSubmatchIndex(line) + } + } else { + for _, prefix := range s.LinkifyConfig.AllowedProtocols { + if bytes.HasPrefix(line, prefix) { + m = s.LinkifyConfig.URLRegexp.FindSubmatchIndex(line) + break + } + } + } + if m == nil && bytes.HasPrefix(line, domainWWW) { + m = s.LinkifyConfig.WWWRegexp.FindSubmatchIndex(line) + protocol = []byte("http") + } + if m != nil && m[0] != 0 { + m = nil + } + if m != nil && m[0] == 0 { + lastChar := line[m[1]-1] + if lastChar == '.' { + m[1]-- + } else if lastChar == ')' { + closing := 0 + for i := m[1] - 1; i >= m[0]; i-- { + if line[i] == ')' { + closing++ + } else if line[i] == '(' { + closing-- + } + } + if closing > 0 { + m[1] -= closing + } + } else if lastChar == ';' { + i := m[1] - 2 + for ; i >= m[0]; i-- { + if util.IsAlphaNumeric(line[i]) { + continue + } + break + } + if i != m[1]-2 { + if line[i] == '&' { + m[1] -= m[1] - i + } + } + } + } + if m == nil { + if len(line) > 0 && util.IsPunct(line[0]) { + return nil + } + typ = ast.AutoLinkEmail + stop := -1 + if s.LinkifyConfig.EmailRegexp == nil { + stop = util.FindEmailIndex(line) + } else { + m := s.LinkifyConfig.EmailRegexp.FindSubmatchIndex(line) + if m != nil && m[0] == 0 { + stop = m[1] + } + } + if stop < 0 { + return nil + } + at := bytes.IndexByte(line, '@') + m = []int{0, stop, at, stop - 1} + if m == nil || bytes.IndexByte(line[m[2]:m[3]], '.') < 0 { + return nil + } + lastChar := line[m[1]-1] + if lastChar == '.' { + m[1]-- + } + if m[1] < len(line) { + nextChar := line[m[1]] + if nextChar == '-' || nextChar == '_' { + return nil + } + } + } + if m == nil { + return nil + } + if consumes != 0 { + s := segment.WithStop(segment.Start + 1) + ast.MergeOrAppendTextSegment(parent, s) + } + consumes += m[1] + block.Advance(consumes) + n := ast.NewTextSegment(text.NewSegment(start, start+m[1])) + link := ast.NewAutoLink(typ, n) + link.Protocol = protocol + return link +} + +func (s *linkifyParser) CloseBlock(parent ast.Node, pc parser.Context) { + // nothing to do +} + +type linkify struct { + options []LinkifyOption +} + +// Linkify is an extension that allow you to parse text that seems like a URL. +var Linkify = &linkify{} + +func NewLinkify(opts ...LinkifyOption) goldmark.Extender { + return &linkify{ + options: opts, + } +} + +func (e *linkify) Extend(m goldmark.Markdown) { + m.Parser().AddOptions( + parser.WithInlineParsers( + util.Prioritized(NewLinkifyParser(e.options...), 999), + ), + ) +} diff --git a/vendor/github.com/yuin/goldmark/extension/strikethrough.go b/vendor/github.com/yuin/goldmark/extension/strikethrough.go new file mode 100644 index 0000000000..1b629ad8ff --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/strikethrough.go @@ -0,0 +1,116 @@ +package extension + +import ( + "github.com/yuin/goldmark" + gast "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type strikethroughDelimiterProcessor struct { +} + +func (p *strikethroughDelimiterProcessor) IsDelimiter(b byte) bool { + return b == '~' +} + +func (p *strikethroughDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool { + return opener.Char == closer.Char +} + +func (p *strikethroughDelimiterProcessor) OnMatch(consumes int) gast.Node { + return ast.NewStrikethrough() +} + +var defaultStrikethroughDelimiterProcessor = &strikethroughDelimiterProcessor{} + +type strikethroughParser struct { +} + +var defaultStrikethroughParser = &strikethroughParser{} + +// NewStrikethroughParser return a new InlineParser that parses +// strikethrough expressions. +func NewStrikethroughParser() parser.InlineParser { + return defaultStrikethroughParser +} + +func (s *strikethroughParser) Trigger() []byte { + return []byte{'~'} +} + +func (s *strikethroughParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { + before := block.PrecendingCharacter() + line, segment := block.PeekLine() + node := parser.ScanDelimiter(line, before, 2, defaultStrikethroughDelimiterProcessor) + if node == nil { + return nil + } + node.Segment = segment.WithStop(segment.Start + node.OriginalLength) + block.Advance(node.OriginalLength) + pc.PushDelimiter(node) + return node +} + +func (s *strikethroughParser) CloseBlock(parent gast.Node, pc parser.Context) { + // nothing to do +} + +// StrikethroughHTMLRenderer is a renderer.NodeRenderer implementation that +// renders Strikethrough nodes. +type StrikethroughHTMLRenderer struct { + html.Config +} + +// NewStrikethroughHTMLRenderer returns a new StrikethroughHTMLRenderer. +func NewStrikethroughHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { + r := &StrikethroughHTMLRenderer{ + Config: html.NewConfig(), + } + for _, opt := range opts { + opt.SetHTMLOption(&r.Config) + } + return r +} + +// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. +func (r *StrikethroughHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(ast.KindStrikethrough, r.renderStrikethrough) +} + +// StrikethroughAttributeFilter defines attribute names which dd elements can have. +var StrikethroughAttributeFilter = html.GlobalAttributeFilter + +func (r *StrikethroughHTMLRenderer) renderStrikethrough(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("") + } + } else { + _, _ = w.WriteString("") + } + return gast.WalkContinue, nil +} + +type strikethrough struct { +} + +// Strikethrough is an extension that allow you to use strikethrough expression like '~~text~~' . +var Strikethrough = &strikethrough{} + +func (e *strikethrough) Extend(m goldmark.Markdown) { + m.Parser().AddOptions(parser.WithInlineParsers( + util.Prioritized(NewStrikethroughParser(), 500), + )) + m.Renderer().AddOptions(renderer.WithNodeRenderers( + util.Prioritized(NewStrikethroughHTMLRenderer(), 500), + )) +} diff --git a/vendor/github.com/yuin/goldmark/extension/table.go b/vendor/github.com/yuin/goldmark/extension/table.go new file mode 100644 index 0000000000..c637b99f04 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/table.go @@ -0,0 +1,552 @@ +package extension + +import ( + "bytes" + "fmt" + "regexp" + + "github.com/yuin/goldmark" + gast "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var escapedPipeCellListKey = parser.NewContextKey() + +type escapedPipeCell struct { + Cell *ast.TableCell + Pos []int + Transformed bool +} + +// TableCellAlignMethod indicates how are table cells aligned in HTML format.indicates how are table cells aligned in HTML format. +type TableCellAlignMethod int + +const ( + // TableCellAlignDefault renders alignments by default method. + // With XHTML, alignments are rendered as an align attribute. + // With HTML5, alignments are rendered as a style attribute. + TableCellAlignDefault TableCellAlignMethod = iota + + // TableCellAlignAttribute renders alignments as an align attribute. + TableCellAlignAttribute + + // TableCellAlignStyle renders alignments as a style attribute. + TableCellAlignStyle + + // TableCellAlignNone does not care about alignments. + // If you using classes or other styles, you can add these attributes + // in an ASTTransformer. + TableCellAlignNone +) + +// TableConfig struct holds options for the extension. +type TableConfig struct { + html.Config + + // TableCellAlignMethod indicates how are table celss aligned. + TableCellAlignMethod TableCellAlignMethod +} + +// TableOption interface is a functional option interface for the extension. +type TableOption interface { + renderer.Option + // SetTableOption sets given option to the extension. + SetTableOption(*TableConfig) +} + +// NewTableConfig returns a new Config with defaults. +func NewTableConfig() TableConfig { + return TableConfig{ + Config: html.NewConfig(), + TableCellAlignMethod: TableCellAlignDefault, + } +} + +// SetOption implements renderer.SetOptioner. +func (c *TableConfig) SetOption(name renderer.OptionName, value interface{}) { + switch name { + case optTableCellAlignMethod: + c.TableCellAlignMethod = value.(TableCellAlignMethod) + default: + c.Config.SetOption(name, value) + } +} + +type withTableHTMLOptions struct { + value []html.Option +} + +func (o *withTableHTMLOptions) SetConfig(c *renderer.Config) { + if o.value != nil { + for _, v := range o.value { + v.(renderer.Option).SetConfig(c) + } + } +} + +func (o *withTableHTMLOptions) SetTableOption(c *TableConfig) { + if o.value != nil { + for _, v := range o.value { + v.SetHTMLOption(&c.Config) + } + } +} + +// WithTableHTMLOptions is functional option that wraps goldmark HTMLRenderer options. +func WithTableHTMLOptions(opts ...html.Option) TableOption { + return &withTableHTMLOptions{opts} +} + +const optTableCellAlignMethod renderer.OptionName = "TableTableCellAlignMethod" + +type withTableCellAlignMethod struct { + value TableCellAlignMethod +} + +func (o *withTableCellAlignMethod) SetConfig(c *renderer.Config) { + c.Options[optTableCellAlignMethod] = o.value +} + +func (o *withTableCellAlignMethod) SetTableOption(c *TableConfig) { + c.TableCellAlignMethod = o.value +} + +// WithTableCellAlignMethod is a functional option that indicates how are table cells aligned in HTML format. +func WithTableCellAlignMethod(a TableCellAlignMethod) TableOption { + return &withTableCellAlignMethod{a} +} + +func isTableDelim(bs []byte) bool { + for _, b := range bs { + if !(util.IsSpace(b) || b == '-' || b == '|' || b == ':') { + return false + } + } + return true +} + +var tableDelimLeft = regexp.MustCompile(`^\s*\:\-+\s*$`) +var tableDelimRight = regexp.MustCompile(`^\s*\-+\:\s*$`) +var tableDelimCenter = regexp.MustCompile(`^\s*\:\-+\:\s*$`) +var tableDelimNone = regexp.MustCompile(`^\s*\-+\s*$`) + +type tableParagraphTransformer struct { +} + +var defaultTableParagraphTransformer = &tableParagraphTransformer{} + +// NewTableParagraphTransformer returns a new ParagraphTransformer +// that can transform paragraphs into tables. +func NewTableParagraphTransformer() parser.ParagraphTransformer { + return defaultTableParagraphTransformer +} + +func (b *tableParagraphTransformer) Transform(node *gast.Paragraph, reader text.Reader, pc parser.Context) { + lines := node.Lines() + if lines.Len() < 2 { + return + } + for i := 1; i < lines.Len(); i++ { + alignments := b.parseDelimiter(lines.At(i), reader) + if alignments == nil { + continue + } + header := b.parseRow(lines.At(i-1), alignments, true, reader, pc) + if header == nil || len(alignments) != header.ChildCount() { + return + } + table := ast.NewTable() + table.Alignments = alignments + table.AppendChild(table, ast.NewTableHeader(header)) + for j := i + 1; j < lines.Len(); j++ { + table.AppendChild(table, b.parseRow(lines.At(j), alignments, false, reader, pc)) + } + node.Lines().SetSliced(0, i-1) + node.Parent().InsertAfter(node.Parent(), node, table) + if node.Lines().Len() == 0 { + node.Parent().RemoveChild(node.Parent(), node) + } else { + last := node.Lines().At(i - 2) + last.Stop = last.Stop - 1 // trim last newline(\n) + node.Lines().Set(i-2, last) + } + } +} + +func (b *tableParagraphTransformer) parseRow(segment text.Segment, alignments []ast.Alignment, isHeader bool, reader text.Reader, pc parser.Context) *ast.TableRow { + source := reader.Source() + line := segment.Value(source) + pos := 0 + pos += util.TrimLeftSpaceLength(line) + limit := len(line) + limit -= util.TrimRightSpaceLength(line) + row := ast.NewTableRow(alignments) + if len(line) > 0 && line[pos] == '|' { + pos++ + } + if len(line) > 0 && line[limit-1] == '|' { + limit-- + } + i := 0 + for ; pos < limit; i++ { + alignment := ast.AlignNone + if i >= len(alignments) { + if !isHeader { + return row + } + } else { + alignment = alignments[i] + } + + var escapedCell *escapedPipeCell + node := ast.NewTableCell() + node.Alignment = alignment + hasBacktick := false + closure := pos + for ; closure < limit; closure++ { + if line[closure] == '`' { + hasBacktick = true + } + if line[closure] == '|' { + if closure == 0 || line[closure-1] != '\\' { + break + } else if hasBacktick { + if escapedCell == nil { + escapedCell = &escapedPipeCell{node, []int{}, false} + escapedList := pc.ComputeIfAbsent(escapedPipeCellListKey, + func() interface{} { + return []*escapedPipeCell{} + }).([]*escapedPipeCell) + escapedList = append(escapedList, escapedCell) + pc.Set(escapedPipeCellListKey, escapedList) + } + escapedCell.Pos = append(escapedCell.Pos, segment.Start+closure-1) + } + } + } + seg := text.NewSegment(segment.Start+pos, segment.Start+closure) + seg = seg.TrimLeftSpace(source) + seg = seg.TrimRightSpace(source) + node.Lines().Append(seg) + row.AppendChild(row, node) + pos = closure + 1 + } + for ; i < len(alignments); i++ { + row.AppendChild(row, ast.NewTableCell()) + } + return row +} + +func (b *tableParagraphTransformer) parseDelimiter(segment text.Segment, reader text.Reader) []ast.Alignment { + line := segment.Value(reader.Source()) + if !isTableDelim(line) { + return nil + } + cols := bytes.Split(line, []byte{'|'}) + if util.IsBlank(cols[0]) { + cols = cols[1:] + } + if len(cols) > 0 && util.IsBlank(cols[len(cols)-1]) { + cols = cols[:len(cols)-1] + } + + var alignments []ast.Alignment + for _, col := range cols { + if tableDelimLeft.Match(col) { + alignments = append(alignments, ast.AlignLeft) + } else if tableDelimRight.Match(col) { + alignments = append(alignments, ast.AlignRight) + } else if tableDelimCenter.Match(col) { + alignments = append(alignments, ast.AlignCenter) + } else if tableDelimNone.Match(col) { + alignments = append(alignments, ast.AlignNone) + } else { + return nil + } + } + return alignments +} + +type tableASTTransformer struct { +} + +var defaultTableASTTransformer = &tableASTTransformer{} + +// NewTableASTTransformer returns a parser.ASTTransformer for tables. +func NewTableASTTransformer() parser.ASTTransformer { + return defaultTableASTTransformer +} + +func (a *tableASTTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) { + lst := pc.Get(escapedPipeCellListKey) + if lst == nil { + return + } + pc.Set(escapedPipeCellListKey, nil) + for _, v := range lst.([]*escapedPipeCell) { + if v.Transformed { + continue + } + _ = gast.Walk(v.Cell, func(n gast.Node, entering bool) (gast.WalkStatus, error) { + if !entering || n.Kind() != gast.KindCodeSpan { + return gast.WalkContinue, nil + } + + for c := n.FirstChild(); c != nil; { + next := c.NextSibling() + if c.Kind() != gast.KindText { + c = next + continue + } + parent := c.Parent() + ts := &c.(*gast.Text).Segment + n := c + for _, v := range lst.([]*escapedPipeCell) { + for _, pos := range v.Pos { + if ts.Start <= pos && pos < ts.Stop { + segment := n.(*gast.Text).Segment + n1 := gast.NewRawTextSegment(segment.WithStop(pos)) + n2 := gast.NewRawTextSegment(segment.WithStart(pos + 1)) + parent.InsertAfter(parent, n, n1) + parent.InsertAfter(parent, n1, n2) + parent.RemoveChild(parent, n) + n = n2 + v.Transformed = true + } + } + } + c = next + } + return gast.WalkContinue, nil + }) + } +} + +// TableHTMLRenderer is a renderer.NodeRenderer implementation that +// renders Table nodes. +type TableHTMLRenderer struct { + TableConfig +} + +// NewTableHTMLRenderer returns a new TableHTMLRenderer. +func NewTableHTMLRenderer(opts ...TableOption) renderer.NodeRenderer { + r := &TableHTMLRenderer{ + TableConfig: NewTableConfig(), + } + for _, opt := range opts { + opt.SetTableOption(&r.TableConfig) + } + return r +} + +// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. +func (r *TableHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(ast.KindTable, r.renderTable) + reg.Register(ast.KindTableHeader, r.renderTableHeader) + reg.Register(ast.KindTableRow, r.renderTableRow) + reg.Register(ast.KindTableCell, r.renderTableCell) +} + +// TableAttributeFilter defines attribute names which table elements can have. +var TableAttributeFilter = html.GlobalAttributeFilter.Extend( + []byte("align"), // [Deprecated] + []byte("bgcolor"), // [Deprecated] + []byte("border"), // [Deprecated] + []byte("cellpadding"), // [Deprecated] + []byte("cellspacing"), // [Deprecated] + []byte("frame"), // [Deprecated] + []byte("rules"), // [Deprecated] + []byte("summary"), // [Deprecated] + []byte("width"), // [Deprecated] +) + +func (r *TableHTMLRenderer) renderTable(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + _, _ = w.WriteString("\n") + } else { + _, _ = w.WriteString("\n") + } + return gast.WalkContinue, nil +} + +// TableHeaderAttributeFilter defines attribute names which elements can have. +var TableHeaderAttributeFilter = html.GlobalAttributeFilter.Extend( + []byte("align"), // [Deprecated since HTML4] [Obsolete since HTML5] + []byte("bgcolor"), // [Not Standardized] + []byte("char"), // [Deprecated since HTML4] [Obsolete since HTML5] + []byte("charoff"), // [Deprecated since HTML4] [Obsolete since HTML5] + []byte("valign"), // [Deprecated since HTML4] [Obsolete since HTML5] +) + +func (r *TableHTMLRenderer) renderTableHeader(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + _, _ = w.WriteString("\n") + _, _ = w.WriteString("\n") // Header has no separate handle + } else { + _, _ = w.WriteString("\n") + _, _ = w.WriteString("\n") + if n.NextSibling() != nil { + _, _ = w.WriteString("\n") + } + } + return gast.WalkContinue, nil +} + +// TableRowAttributeFilter defines attribute names which elements can have. +var TableRowAttributeFilter = html.GlobalAttributeFilter.Extend( + []byte("align"), // [Obsolete since HTML5] + []byte("bgcolor"), // [Obsolete since HTML5] + []byte("char"), // [Obsolete since HTML5] + []byte("charoff"), // [Obsolete since HTML5] + []byte("valign"), // [Obsolete since HTML5] +) + +func (r *TableHTMLRenderer) renderTableRow(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { + if entering { + _, _ = w.WriteString("\n") + } else { + _, _ = w.WriteString("\n") + if n.Parent().LastChild() == n { + _, _ = w.WriteString("\n") + } + } + return gast.WalkContinue, nil +} + +// TableThCellAttributeFilter defines attribute names which table cells can have. +var TableThCellAttributeFilter = html.GlobalAttributeFilter.Extend( + []byte("abbr"), // [OK] Contains a short abbreviated description of the cell's content [NOT OK in ] + + []byte("align"), // [Obsolete since HTML5] + []byte("axis"), // [Obsolete since HTML5] + []byte("bgcolor"), // [Not Standardized] + []byte("char"), // [Obsolete since HTML5] + []byte("charoff"), // [Obsolete since HTML5] + + []byte("colspan"), // [OK] Number of columns that the cell is to span + []byte("headers"), // [OK] This attribute contains a list of space-separated strings, each corresponding to the id attribute of the elements that apply to this element + + []byte("height"), // [Deprecated since HTML4] [Obsolete since HTML5] + + []byte("rowspan"), // [OK] Number of rows that the cell is to span + []byte("scope"), // [OK] This enumerated attribute defines the cells that the header (defined in the ) element relates to [NOT OK in ] + + []byte("valign"), // [Obsolete since HTML5] + []byte("width"), // [Deprecated since HTML4] [Obsolete since HTML5] +) + +// TableTdCellAttributeFilter defines attribute names which table cells can have. +var TableTdCellAttributeFilter = html.GlobalAttributeFilter.Extend( + []byte("abbr"), // [Obsolete since HTML5] [OK in ] + []byte("align"), // [Obsolete since HTML5] + []byte("axis"), // [Obsolete since HTML5] + []byte("bgcolor"), // [Not Standardized] + []byte("char"), // [Obsolete since HTML5] + []byte("charoff"), // [Obsolete since HTML5] + + []byte("colspan"), // [OK] Number of columns that the cell is to span + []byte("headers"), // [OK] This attribute contains a list of space-separated strings, each corresponding to the id attribute of the elements that apply to this element + + []byte("height"), // [Deprecated since HTML4] [Obsolete since HTML5] + + []byte("rowspan"), // [OK] Number of rows that the cell is to span + + []byte("scope"), // [Obsolete since HTML5] [OK in ] + []byte("valign"), // [Obsolete since HTML5] + []byte("width"), // [Deprecated since HTML4] [Obsolete since HTML5] +) + +func (r *TableHTMLRenderer) renderTableCell(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { + n := node.(*ast.TableCell) + tag := "td" + if n.Parent().Kind() == ast.KindTableHeader { + tag = "th" + } + if entering { + fmt.Fprintf(w, "<%s", tag) + if n.Alignment != ast.AlignNone { + amethod := r.TableConfig.TableCellAlignMethod + if amethod == TableCellAlignDefault { + if r.Config.XHTML { + amethod = TableCellAlignAttribute + } else { + amethod = TableCellAlignStyle + } + } + switch amethod { + case TableCellAlignAttribute: + if _, ok := n.AttributeString("align"); !ok { // Skip align render if overridden + fmt.Fprintf(w, ` align="%s"`, n.Alignment.String()) + } + case TableCellAlignStyle: + v, ok := n.AttributeString("style") + var cob util.CopyOnWriteBuffer + if ok { + cob = util.NewCopyOnWriteBuffer(v.([]byte)) + cob.AppendByte(';') + } + style := fmt.Sprintf("text-align:%s", n.Alignment.String()) + cob.AppendString(style) + n.SetAttributeString("style", cob.Bytes()) + } + } + if n.Attributes() != nil { + if tag == "td" { + html.RenderAttributes(w, n, TableTdCellAttributeFilter) // + } else { + html.RenderAttributes(w, n, TableThCellAttributeFilter) // + } + } + _ = w.WriteByte('>') + } else { + fmt.Fprintf(w, "\n", tag) + } + return gast.WalkContinue, nil +} + +type table struct { + options []TableOption +} + +// Table is an extension that allow you to use GFM tables . +var Table = &table{ + options: []TableOption{}, +} + +// NewTable returns a new extension with given options. +func NewTable(opts ...TableOption) goldmark.Extender { + return &table{ + options: opts, + } +} + +func (e *table) Extend(m goldmark.Markdown) { + m.Parser().AddOptions( + parser.WithParagraphTransformers( + util.Prioritized(NewTableParagraphTransformer(), 200), + ), + parser.WithASTTransformers( + util.Prioritized(defaultTableASTTransformer, 0), + ), + ) + m.Renderer().AddOptions(renderer.WithNodeRenderers( + util.Prioritized(NewTableHTMLRenderer(e.options...), 500), + )) +} diff --git a/vendor/github.com/yuin/goldmark/extension/tasklist.go b/vendor/github.com/yuin/goldmark/extension/tasklist.go new file mode 100644 index 0000000000..1f3e52c204 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/tasklist.go @@ -0,0 +1,115 @@ +package extension + +import ( + "github.com/yuin/goldmark" + gast "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" + "regexp" +) + +var taskListRegexp = regexp.MustCompile(`^\[([\sxX])\]\s*`) + +type taskCheckBoxParser struct { +} + +var defaultTaskCheckBoxParser = &taskCheckBoxParser{} + +// NewTaskCheckBoxParser returns a new InlineParser that can parse +// checkboxes in list items. +// This parser must take precedence over the parser.LinkParser. +func NewTaskCheckBoxParser() parser.InlineParser { + return defaultTaskCheckBoxParser +} + +func (s *taskCheckBoxParser) Trigger() []byte { + return []byte{'['} +} + +func (s *taskCheckBoxParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { + // Given AST structure must be like + // - List + // - ListItem : parent.Parent + // - TextBlock : parent + // (current line) + if parent.Parent() == nil || parent.Parent().FirstChild() != parent { + return nil + } + + if _, ok := parent.Parent().(*gast.ListItem); !ok { + return nil + } + line, _ := block.PeekLine() + m := taskListRegexp.FindSubmatchIndex(line) + if m == nil { + return nil + } + value := line[m[2]:m[3]][0] + block.Advance(m[1]) + checked := value == 'x' || value == 'X' + return ast.NewTaskCheckBox(checked) +} + +func (s *taskCheckBoxParser) CloseBlock(parent gast.Node, pc parser.Context) { + // nothing to do +} + +// TaskCheckBoxHTMLRenderer is a renderer.NodeRenderer implementation that +// renders checkboxes in list items. +type TaskCheckBoxHTMLRenderer struct { + html.Config +} + +// NewTaskCheckBoxHTMLRenderer returns a new TaskCheckBoxHTMLRenderer. +func NewTaskCheckBoxHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { + r := &TaskCheckBoxHTMLRenderer{ + Config: html.NewConfig(), + } + for _, opt := range opts { + opt.SetHTMLOption(&r.Config) + } + return r +} + +// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. +func (r *TaskCheckBoxHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(ast.KindTaskCheckBox, r.renderTaskCheckBox) +} + +func (r *TaskCheckBoxHTMLRenderer) renderTaskCheckBox(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { + if !entering { + return gast.WalkContinue, nil + } + n := node.(*ast.TaskCheckBox) + + if n.IsChecked { + w.WriteString(` ") + } else { + w.WriteString("> ") + } + return gast.WalkContinue, nil +} + +type taskList struct { +} + +// TaskList is an extension that allow you to use GFM task lists. +var TaskList = &taskList{} + +func (e *taskList) Extend(m goldmark.Markdown) { + m.Parser().AddOptions(parser.WithInlineParsers( + util.Prioritized(NewTaskCheckBoxParser(), 0), + )) + m.Renderer().AddOptions(renderer.WithNodeRenderers( + util.Prioritized(NewTaskCheckBoxHTMLRenderer(), 500), + )) +} diff --git a/vendor/github.com/yuin/goldmark/extension/typographer.go b/vendor/github.com/yuin/goldmark/extension/typographer.go new file mode 100644 index 0000000000..2c34730944 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/extension/typographer.go @@ -0,0 +1,323 @@ +package extension + +import ( + "unicode" + + "github.com/yuin/goldmark" + gast "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var uncloseCounterKey = parser.NewContextKey() + +type unclosedCounter struct { + Single int + Double int +} + +func (u *unclosedCounter) Reset() { + u.Single = 0 + u.Double = 0 +} + +func getUnclosedCounter(pc parser.Context) *unclosedCounter { + v := pc.Get(uncloseCounterKey) + if v == nil { + v = &unclosedCounter{} + pc.Set(uncloseCounterKey, v) + } + return v.(*unclosedCounter) +} + +// TypographicPunctuation is a key of the punctuations that can be replaced with +// typographic entities. +type TypographicPunctuation int + +const ( + // LeftSingleQuote is ' + LeftSingleQuote TypographicPunctuation = iota + 1 + // RightSingleQuote is ' + RightSingleQuote + // LeftDoubleQuote is " + LeftDoubleQuote + // RightDoubleQuote is " + RightDoubleQuote + // EnDash is -- + EnDash + // EmDash is --- + EmDash + // Ellipsis is ... + Ellipsis + // LeftAngleQuote is << + LeftAngleQuote + // RightAngleQuote is >> + RightAngleQuote + // Apostrophe is ' + Apostrophe + + typographicPunctuationMax +) + +// An TypographerConfig struct is a data structure that holds configuration of the +// Typographer extension. +type TypographerConfig struct { + Substitutions [][]byte +} + +func newDefaultSubstitutions() [][]byte { + replacements := make([][]byte, typographicPunctuationMax) + replacements[LeftSingleQuote] = []byte("‘") + replacements[RightSingleQuote] = []byte("’") + replacements[LeftDoubleQuote] = []byte("“") + replacements[RightDoubleQuote] = []byte("”") + replacements[EnDash] = []byte("–") + replacements[EmDash] = []byte("—") + replacements[Ellipsis] = []byte("…") + replacements[LeftAngleQuote] = []byte("«") + replacements[RightAngleQuote] = []byte("»") + replacements[Apostrophe] = []byte("’") + + return replacements +} + +// SetOption implements SetOptioner. +func (b *TypographerConfig) SetOption(name parser.OptionName, value interface{}) { + switch name { + case optTypographicSubstitutions: + b.Substitutions = value.([][]byte) + } +} + +// A TypographerOption interface sets options for the TypographerParser. +type TypographerOption interface { + parser.Option + SetTypographerOption(*TypographerConfig) +} + +const optTypographicSubstitutions parser.OptionName = "TypographicSubstitutions" + +// TypographicSubstitutions is a list of the substitutions for the Typographer extension. +type TypographicSubstitutions map[TypographicPunctuation][]byte + +type withTypographicSubstitutions struct { + value [][]byte +} + +func (o *withTypographicSubstitutions) SetParserOption(c *parser.Config) { + c.Options[optTypographicSubstitutions] = o.value +} + +func (o *withTypographicSubstitutions) SetTypographerOption(p *TypographerConfig) { + p.Substitutions = o.value +} + +// WithTypographicSubstitutions is a functional otpion that specify replacement text +// for punctuations. +func WithTypographicSubstitutions(values map[TypographicPunctuation][]byte) TypographerOption { + replacements := newDefaultSubstitutions() + for k, v := range values { + replacements[k] = v + } + + return &withTypographicSubstitutions{replacements} +} + +type typographerDelimiterProcessor struct { +} + +func (p *typographerDelimiterProcessor) IsDelimiter(b byte) bool { + return b == '\'' || b == '"' +} + +func (p *typographerDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool { + return opener.Char == closer.Char +} + +func (p *typographerDelimiterProcessor) OnMatch(consumes int) gast.Node { + return nil +} + +var defaultTypographerDelimiterProcessor = &typographerDelimiterProcessor{} + +type typographerParser struct { + TypographerConfig +} + +// NewTypographerParser return a new InlineParser that parses +// typographer expressions. +func NewTypographerParser(opts ...TypographerOption) parser.InlineParser { + p := &typographerParser{ + TypographerConfig: TypographerConfig{ + Substitutions: newDefaultSubstitutions(), + }, + } + for _, o := range opts { + o.SetTypographerOption(&p.TypographerConfig) + } + return p +} + +func (s *typographerParser) Trigger() []byte { + return []byte{'\'', '"', '-', '.', '<', '>'} +} + +func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { + line, _ := block.PeekLine() + c := line[0] + if len(line) > 2 { + if c == '-' { + if s.Substitutions[EmDash] != nil && line[1] == '-' && line[2] == '-' { // --- + node := gast.NewString(s.Substitutions[EmDash]) + node.SetCode(true) + block.Advance(3) + return node + } + } else if c == '.' { + if s.Substitutions[Ellipsis] != nil && line[1] == '.' && line[2] == '.' { // ... + node := gast.NewString(s.Substitutions[Ellipsis]) + node.SetCode(true) + block.Advance(3) + return node + } + return nil + } + } + if len(line) > 1 { + if c == '<' { + if s.Substitutions[LeftAngleQuote] != nil && line[1] == '<' { // << + node := gast.NewString(s.Substitutions[LeftAngleQuote]) + node.SetCode(true) + block.Advance(2) + return node + } + return nil + } else if c == '>' { + if s.Substitutions[RightAngleQuote] != nil && line[1] == '>' { // >> + node := gast.NewString(s.Substitutions[RightAngleQuote]) + node.SetCode(true) + block.Advance(2) + return node + } + return nil + } else if s.Substitutions[EnDash] != nil && c == '-' && line[1] == '-' { // -- + node := gast.NewString(s.Substitutions[EnDash]) + node.SetCode(true) + block.Advance(2) + return node + } + } + if c == '\'' || c == '"' { + before := block.PrecendingCharacter() + d := parser.ScanDelimiter(line, before, 1, defaultTypographerDelimiterProcessor) + if d == nil { + return nil + } + counter := getUnclosedCounter(pc) + if c == '\'' { + if s.Substitutions[Apostrophe] != nil { + // Handle decade abbrevations such as '90s + if d.CanOpen && !d.CanClose && len(line) > 3 && util.IsNumeric(line[1]) && util.IsNumeric(line[2]) && line[3] == 's' { + after := rune(' ') + if len(line) > 4 { + after = util.ToRune(line, 4) + } + if len(line) == 3 || util.IsSpaceRune(after) || util.IsPunctRune(after) { + node := gast.NewString(s.Substitutions[Apostrophe]) + node.SetCode(true) + block.Advance(1) + return node + } + } + // Convert normal apostrophes. This is probably more flexible than necessary but + // converts any apostrophe in between two alphanumerics. + if len(line) > 1 && (unicode.IsDigit(before) || unicode.IsLetter(before)) && (unicode.IsLetter(util.ToRune(line, 1))) { + node := gast.NewString(s.Substitutions[Apostrophe]) + node.SetCode(true) + block.Advance(1) + return node + } + } + if s.Substitutions[LeftSingleQuote] != nil && d.CanOpen && !d.CanClose { + nt := LeftSingleQuote + // special cases: Alice's, I'm ,Don't, You'd + if len(line) > 1 && (line[1] == 's' || line[1] == 'm' || line[1] == 't' || line[1] == 'd') && (len(line) < 3 || util.IsPunct(line[2]) || util.IsSpace(line[2])) { + nt = RightSingleQuote + } + // special cases: I've, I'll, You're + if len(line) > 2 && ((line[1] == 'v' && line[2] == 'e') || (line[1] == 'l' && line[2] == 'l') || (line[1] == 'r' && line[2] == 'e')) && (len(line) < 4 || util.IsPunct(line[3]) || util.IsSpace(line[3])) { + nt = RightSingleQuote + } + if nt == LeftSingleQuote { + counter.Single++ + } + + node := gast.NewString(s.Substitutions[nt]) + node.SetCode(true) + block.Advance(1) + return node + } + if s.Substitutions[RightSingleQuote] != nil && counter.Single > 0 { + isClose := d.CanClose && !d.CanOpen + maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && (line[1] == ',' || line[1] == '.' || line[1] == '!' || line[1] == '?') && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) + if isClose || maybeClose { + node := gast.NewString(s.Substitutions[RightSingleQuote]) + node.SetCode(true) + block.Advance(1) + counter.Single-- + return node + } + } + } + if c == '"' { + if s.Substitutions[LeftDoubleQuote] != nil && d.CanOpen && !d.CanClose { + node := gast.NewString(s.Substitutions[LeftDoubleQuote]) + node.SetCode(true) + block.Advance(1) + counter.Double++ + return node + } + if s.Substitutions[RightDoubleQuote] != nil && counter.Double > 0 { + isClose := d.CanClose && !d.CanOpen + maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && (line[1] == ',' || line[1] == '.' || line[1] == '!' || line[1] == '?') && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) + if isClose || maybeClose { + // special case: "Monitor 21"" + if len(line) > 1 && line[1] == '"' && unicode.IsDigit(before) { + return nil + } + node := gast.NewString(s.Substitutions[RightDoubleQuote]) + node.SetCode(true) + block.Advance(1) + counter.Double-- + return node + } + } + } + } + return nil +} + +func (s *typographerParser) CloseBlock(parent gast.Node, pc parser.Context) { + getUnclosedCounter(pc).Reset() +} + +type typographer struct { + options []TypographerOption +} + +// Typographer is an extension that replaces punctuations with typographic entities. +var Typographer = &typographer{} + +// NewTypographer returns a new Extender that replaces punctuations with typographic entities. +func NewTypographer(opts ...TypographerOption) goldmark.Extender { + return &typographer{ + options: opts, + } +} + +func (e *typographer) Extend(m goldmark.Markdown) { + m.Parser().AddOptions(parser.WithInlineParsers( + util.Prioritized(NewTypographerParser(e.options...), 9999), + )) +} diff --git a/vendor/github.com/yuin/goldmark/go.mod b/vendor/github.com/yuin/goldmark/go.mod new file mode 100644 index 0000000000..f76c1766fc --- /dev/null +++ b/vendor/github.com/yuin/goldmark/go.mod @@ -0,0 +1,3 @@ +module github.com/yuin/goldmark + +go 1.15 diff --git a/vendor/github.com/yuin/goldmark/go.sum b/vendor/github.com/yuin/goldmark/go.sum new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/yuin/goldmark/markdown.go b/vendor/github.com/yuin/goldmark/markdown.go new file mode 100644 index 0000000000..86d12e225a --- /dev/null +++ b/vendor/github.com/yuin/goldmark/markdown.go @@ -0,0 +1,140 @@ +// Package goldmark implements functions to convert markdown text to a desired format. +package goldmark + +import ( + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" + "io" +) + +// DefaultParser returns a new Parser that is configured by default values. +func DefaultParser() parser.Parser { + return parser.NewParser(parser.WithBlockParsers(parser.DefaultBlockParsers()...), + parser.WithInlineParsers(parser.DefaultInlineParsers()...), + parser.WithParagraphTransformers(parser.DefaultParagraphTransformers()...), + ) +} + +// DefaultRenderer returns a new Renderer that is configured by default values. +func DefaultRenderer() renderer.Renderer { + return renderer.NewRenderer(renderer.WithNodeRenderers(util.Prioritized(html.NewRenderer(), 1000))) +} + +var defaultMarkdown = New() + +// Convert interprets a UTF-8 bytes source in Markdown and +// write rendered contents to a writer w. +func Convert(source []byte, w io.Writer, opts ...parser.ParseOption) error { + return defaultMarkdown.Convert(source, w, opts...) +} + +// A Markdown interface offers functions to convert Markdown text to +// a desired format. +type Markdown interface { + // Convert interprets a UTF-8 bytes source in Markdown and write rendered + // contents to a writer w. + Convert(source []byte, writer io.Writer, opts ...parser.ParseOption) error + + // Parser returns a Parser that will be used for conversion. + Parser() parser.Parser + + // SetParser sets a Parser to this object. + SetParser(parser.Parser) + + // Parser returns a Renderer that will be used for conversion. + Renderer() renderer.Renderer + + // SetRenderer sets a Renderer to this object. + SetRenderer(renderer.Renderer) +} + +// Option is a functional option type for Markdown objects. +type Option func(*markdown) + +// WithExtensions adds extensions. +func WithExtensions(ext ...Extender) Option { + return func(m *markdown) { + m.extensions = append(m.extensions, ext...) + } +} + +// WithParser allows you to override the default parser. +func WithParser(p parser.Parser) Option { + return func(m *markdown) { + m.parser = p + } +} + +// WithParserOptions applies options for the parser. +func WithParserOptions(opts ...parser.Option) Option { + return func(m *markdown) { + m.parser.AddOptions(opts...) + } +} + +// WithRenderer allows you to override the default renderer. +func WithRenderer(r renderer.Renderer) Option { + return func(m *markdown) { + m.renderer = r + } +} + +// WithRendererOptions applies options for the renderer. +func WithRendererOptions(opts ...renderer.Option) Option { + return func(m *markdown) { + m.renderer.AddOptions(opts...) + } +} + +type markdown struct { + parser parser.Parser + renderer renderer.Renderer + extensions []Extender +} + +// New returns a new Markdown with given options. +func New(options ...Option) Markdown { + md := &markdown{ + parser: DefaultParser(), + renderer: DefaultRenderer(), + extensions: []Extender{}, + } + for _, opt := range options { + opt(md) + } + for _, e := range md.extensions { + e.Extend(md) + } + return md +} + +func (m *markdown) Convert(source []byte, writer io.Writer, opts ...parser.ParseOption) error { + reader := text.NewReader(source) + doc := m.parser.Parse(reader, opts...) + return m.renderer.Render(writer, source, doc) +} + +func (m *markdown) Parser() parser.Parser { + return m.parser +} + +func (m *markdown) SetParser(v parser.Parser) { + m.parser = v +} + +func (m *markdown) Renderer() renderer.Renderer { + return m.renderer +} + +func (m *markdown) SetRenderer(v renderer.Renderer) { + m.renderer = v +} + +// An Extender interface is used for extending Markdown. +type Extender interface { + // Extend extends the Markdown. + Extend(Markdown) +} diff --git a/vendor/github.com/yuin/goldmark/parser/attribute.go b/vendor/github.com/yuin/goldmark/parser/attribute.go new file mode 100644 index 0000000000..f86c83610e --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/attribute.go @@ -0,0 +1,328 @@ +package parser + +import ( + "bytes" + "io" + "strconv" + + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var attrNameID = []byte("id") +var attrNameClass = []byte("class") + +// An Attribute is an attribute of the markdown elements +type Attribute struct { + Name []byte + Value interface{} +} + +// An Attributes is a collection of attributes. +type Attributes []Attribute + +// Find returns a (value, true) if an attribute correspond with given name is found, otherwise (nil, false). +func (as Attributes) Find(name []byte) (interface{}, bool) { + for _, a := range as { + if bytes.Equal(a.Name, name) { + return a.Value, true + } + } + return nil, false +} + +func (as Attributes) findUpdate(name []byte, cb func(v interface{}) interface{}) bool { + for i, a := range as { + if bytes.Equal(a.Name, name) { + as[i].Value = cb(a.Value) + return true + } + } + return false +} + +// ParseAttributes parses attributes into a map. +// ParseAttributes returns a parsed attributes and true if could parse +// attributes, otherwise nil and false. +func ParseAttributes(reader text.Reader) (Attributes, bool) { + savedLine, savedPosition := reader.Position() + reader.SkipSpaces() + if reader.Peek() != '{' { + reader.SetPosition(savedLine, savedPosition) + return nil, false + } + reader.Advance(1) + attrs := Attributes{} + for { + if reader.Peek() == '}' { + reader.Advance(1) + return attrs, true + } + attr, ok := parseAttribute(reader) + if !ok { + reader.SetPosition(savedLine, savedPosition) + return nil, false + } + if bytes.Equal(attr.Name, attrNameClass) { + if !attrs.findUpdate(attrNameClass, func(v interface{}) interface{} { + ret := make([]byte, 0, len(v.([]byte))+1+len(attr.Value.([]byte))) + ret = append(ret, v.([]byte)...) + return append(append(ret, ' '), attr.Value.([]byte)...) + }) { + attrs = append(attrs, attr) + } + } else { + attrs = append(attrs, attr) + } + reader.SkipSpaces() + if reader.Peek() == ',' { + reader.Advance(1) + reader.SkipSpaces() + } + } +} + +func parseAttribute(reader text.Reader) (Attribute, bool) { + reader.SkipSpaces() + c := reader.Peek() + if c == '#' || c == '.' { + reader.Advance(1) + line, _ := reader.PeekLine() + i := 0 + // HTML5 allows any kind of characters as id, but XHTML restricts characters for id. + // CommonMark is basically defined for XHTML(even though it is legacy). + // So we restrict id characters. + for ; i < len(line) && !util.IsSpace(line[i]) && + (!util.IsPunct(line[i]) || line[i] == '_' || line[i] == '-' || line[i] == ':' || line[i] == '.'); i++ { + } + name := attrNameClass + if c == '#' { + name = attrNameID + } + reader.Advance(i) + return Attribute{Name: name, Value: line[0:i]}, true + } + line, _ := reader.PeekLine() + if len(line) == 0 { + return Attribute{}, false + } + c = line[0] + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + c == '_' || c == ':') { + return Attribute{}, false + } + i := 0 + for ; i < len(line); i++ { + c = line[i] + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_' || c == ':' || c == '.' || c == '-') { + break + } + } + name := line[:i] + reader.Advance(i) + reader.SkipSpaces() + c = reader.Peek() + if c != '=' { + return Attribute{}, false + } + reader.Advance(1) + reader.SkipSpaces() + value, ok := parseAttributeValue(reader) + if !ok { + return Attribute{}, false + } + if bytes.Equal(name, attrNameClass) { + if _, ok = value.([]byte); !ok { + return Attribute{}, false + } + } + return Attribute{Name: name, Value: value}, true +} + +func parseAttributeValue(reader text.Reader) (interface{}, bool) { + reader.SkipSpaces() + c := reader.Peek() + var value interface{} + ok := false + switch c { + case text.EOF: + return Attribute{}, false + case '{': + value, ok = ParseAttributes(reader) + case '[': + value, ok = parseAttributeArray(reader) + case '"': + value, ok = parseAttributeString(reader) + default: + if c == '-' || c == '+' || util.IsNumeric(c) { + value, ok = parseAttributeNumber(reader) + } else { + value, ok = parseAttributeOthers(reader) + } + } + if !ok { + return nil, false + } + return value, true +} + +func parseAttributeArray(reader text.Reader) ([]interface{}, bool) { + reader.Advance(1) // skip [ + ret := []interface{}{} + for i := 0; ; i++ { + c := reader.Peek() + comma := false + if i != 0 && c == ',' { + reader.Advance(1) + comma = true + } + if c == ']' { + if !comma { + reader.Advance(1) + return ret, true + } + return nil, false + } + reader.SkipSpaces() + value, ok := parseAttributeValue(reader) + if !ok { + return nil, false + } + ret = append(ret, value) + reader.SkipSpaces() + } +} + +func parseAttributeString(reader text.Reader) ([]byte, bool) { + reader.Advance(1) // skip " + line, _ := reader.PeekLine() + i := 0 + l := len(line) + var buf bytes.Buffer + for i < l { + c := line[i] + if c == '\\' && i != l-1 { + n := line[i+1] + switch n { + case '"', '/', '\\': + buf.WriteByte(n) + i += 2 + case 'b': + buf.WriteString("\b") + i += 2 + case 'f': + buf.WriteString("\f") + i += 2 + case 'n': + buf.WriteString("\n") + i += 2 + case 'r': + buf.WriteString("\r") + i += 2 + case 't': + buf.WriteString("\t") + i += 2 + default: + buf.WriteByte('\\') + i++ + } + continue + } + if c == '"' { + reader.Advance(i + 1) + return buf.Bytes(), true + } + buf.WriteByte(c) + i++ + } + return nil, false +} + +func scanAttributeDecimal(reader text.Reader, w io.ByteWriter) { + for { + c := reader.Peek() + if util.IsNumeric(c) { + w.WriteByte(c) + } else { + return + } + reader.Advance(1) + } +} + +func parseAttributeNumber(reader text.Reader) (float64, bool) { + sign := 1 + c := reader.Peek() + if c == '-' { + sign = -1 + reader.Advance(1) + } else if c == '+' { + reader.Advance(1) + } + var buf bytes.Buffer + if !util.IsNumeric(reader.Peek()) { + return 0, false + } + scanAttributeDecimal(reader, &buf) + if buf.Len() == 0 { + return 0, false + } + c = reader.Peek() + if c == '.' { + buf.WriteByte(c) + reader.Advance(1) + scanAttributeDecimal(reader, &buf) + } + c = reader.Peek() + if c == 'e' || c == 'E' { + buf.WriteByte(c) + reader.Advance(1) + c = reader.Peek() + if c == '-' || c == '+' { + buf.WriteByte(c) + reader.Advance(1) + } + scanAttributeDecimal(reader, &buf) + } + f, err := strconv.ParseFloat(buf.String(), 10) + if err != nil { + return 0, false + } + return float64(sign) * f, true +} + +var bytesTrue = []byte("true") +var bytesFalse = []byte("false") +var bytesNull = []byte("null") + +func parseAttributeOthers(reader text.Reader) (interface{}, bool) { + line, _ := reader.PeekLine() + c := line[0] + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + c == '_' || c == ':') { + return nil, false + } + i := 0 + for ; i < len(line); i++ { + c := line[i] + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_' || c == ':' || c == '.' || c == '-') { + break + } + } + value := line[:i] + reader.Advance(i) + if bytes.Equal(value, bytesTrue) { + return true, true + } + if bytes.Equal(value, bytesFalse) { + return false, true + } + if bytes.Equal(value, bytesNull) { + return nil, true + } + return value, true +} diff --git a/vendor/github.com/yuin/goldmark/parser/atx_heading.go b/vendor/github.com/yuin/goldmark/parser/atx_heading.go new file mode 100644 index 0000000000..2526088819 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/atx_heading.go @@ -0,0 +1,243 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +// A HeadingConfig struct is a data structure that holds configuration of the renderers related to headings. +type HeadingConfig struct { + AutoHeadingID bool + Attribute bool +} + +// SetOption implements SetOptioner. +func (b *HeadingConfig) SetOption(name OptionName, value interface{}) { + switch name { + case optAutoHeadingID: + b.AutoHeadingID = true + case optAttribute: + b.Attribute = true + } +} + +// A HeadingOption interface sets options for heading parsers. +type HeadingOption interface { + Option + SetHeadingOption(*HeadingConfig) +} + +// AutoHeadingID is an option name that enables auto IDs for headings. +const optAutoHeadingID OptionName = "AutoHeadingID" + +type withAutoHeadingID struct { +} + +func (o *withAutoHeadingID) SetParserOption(c *Config) { + c.Options[optAutoHeadingID] = true +} + +func (o *withAutoHeadingID) SetHeadingOption(p *HeadingConfig) { + p.AutoHeadingID = true +} + +// WithAutoHeadingID is a functional option that enables custom heading ids and +// auto generated heading ids. +func WithAutoHeadingID() HeadingOption { + return &withAutoHeadingID{} +} + +type withHeadingAttribute struct { + Option +} + +func (o *withHeadingAttribute) SetHeadingOption(p *HeadingConfig) { + p.Attribute = true +} + +// WithHeadingAttribute is a functional option that enables custom heading attributes. +func WithHeadingAttribute() HeadingOption { + return &withHeadingAttribute{WithAttribute()} +} + +type atxHeadingParser struct { + HeadingConfig +} + +// NewATXHeadingParser return a new BlockParser that can parse ATX headings. +func NewATXHeadingParser(opts ...HeadingOption) BlockParser { + p := &atxHeadingParser{} + for _, o := range opts { + o.SetHeadingOption(&p.HeadingConfig) + } + return p +} + +func (b *atxHeadingParser) Trigger() []byte { + return []byte{'#'} +} + +func (b *atxHeadingParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + line, segment := reader.PeekLine() + pos := pc.BlockOffset() + if pos < 0 { + return nil, NoChildren + } + i := pos + for ; i < len(line) && line[i] == '#'; i++ { + } + level := i - pos + if i == pos || level > 6 { + return nil, NoChildren + } + l := util.TrimLeftSpaceLength(line[i:]) + if l == 0 { + return nil, NoChildren + } + start := i + l + if start >= len(line) { + start = len(line) - 1 + } + origstart := start + stop := len(line) - util.TrimRightSpaceLength(line) + + node := ast.NewHeading(level) + parsed := false + if b.Attribute { // handles special case like ### heading ### {#id} + start-- + closureClose := -1 + closureOpen := -1 + for j := start; j < stop; { + c := line[j] + if util.IsEscapedPunctuation(line, j) { + j += 2 + } else if util.IsSpace(c) && j < stop-1 && line[j+1] == '#' { + closureOpen = j + 1 + k := j + 1 + for ; k < stop && line[k] == '#'; k++ { + } + closureClose = k + break + } else { + j++ + } + } + if closureClose > 0 { + reader.Advance(closureClose) + attrs, ok := ParseAttributes(reader) + rest, _ := reader.PeekLine() + parsed = ok && util.IsBlank(rest) + if parsed { + for _, attr := range attrs { + node.SetAttribute(attr.Name, attr.Value) + } + node.Lines().Append(text.NewSegment(segment.Start+start+1-segment.Padding, segment.Start+closureOpen-segment.Padding)) + } + } + } + if !parsed { + start = origstart + stop := len(line) - util.TrimRightSpaceLength(line) + if stop <= start { // empty headings like '##[space]' + stop = start + } else { + i = stop - 1 + for ; line[i] == '#' && i >= start; i-- { + } + if i != stop-1 && !util.IsSpace(line[i]) { + i = stop - 1 + } + i++ + stop = i + } + + if len(util.TrimRight(line[start:stop], []byte{'#'})) != 0 { // empty heading like '### ###' + node.Lines().Append(text.NewSegment(segment.Start+start-segment.Padding, segment.Start+stop-segment.Padding)) + } + } + return node, NoChildren +} + +func (b *atxHeadingParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + return Close +} + +func (b *atxHeadingParser) Close(node ast.Node, reader text.Reader, pc Context) { + if b.Attribute { + _, ok := node.AttributeString("id") + if !ok { + parseLastLineAttributes(node, reader, pc) + } + } + + if b.AutoHeadingID { + id, ok := node.AttributeString("id") + if !ok { + generateAutoHeadingID(node.(*ast.Heading), reader, pc) + } else { + pc.IDs().Put(id.([]byte)) + } + } +} + +func (b *atxHeadingParser) CanInterruptParagraph() bool { + return true +} + +func (b *atxHeadingParser) CanAcceptIndentedLine() bool { + return false +} + +func generateAutoHeadingID(node *ast.Heading, reader text.Reader, pc Context) { + var line []byte + lastIndex := node.Lines().Len() - 1 + if lastIndex > -1 { + lastLine := node.Lines().At(lastIndex) + line = lastLine.Value(reader.Source()) + } + headingID := pc.IDs().Generate(line, ast.KindHeading) + node.SetAttribute(attrNameID, headingID) +} + +func parseLastLineAttributes(node ast.Node, reader text.Reader, pc Context) { + lastIndex := node.Lines().Len() - 1 + if lastIndex < 0 { // empty headings + return + } + lastLine := node.Lines().At(lastIndex) + line := lastLine.Value(reader.Source()) + lr := text.NewReader(line) + var attrs Attributes + var ok bool + var start text.Segment + var sl int + var end text.Segment + for { + c := lr.Peek() + if c == text.EOF { + break + } + if c == '\\' { + lr.Advance(1) + if lr.Peek() == '{' { + lr.Advance(1) + } + continue + } + if c == '{' { + sl, start = lr.Position() + attrs, ok = ParseAttributes(lr) + _, end = lr.Position() + lr.SetPosition(sl, start) + } + lr.Advance(1) + } + if ok && util.IsBlank(line[end.Start:]) { + for _, attr := range attrs { + node.SetAttribute(attr.Name, attr.Value) + } + lastLine.Stop = lastLine.Start + start.Start + node.Lines().Set(lastIndex, lastLine) + } +} diff --git a/vendor/github.com/yuin/goldmark/parser/auto_link.go b/vendor/github.com/yuin/goldmark/parser/auto_link.go new file mode 100644 index 0000000000..726a505713 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/auto_link.go @@ -0,0 +1,42 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type autoLinkParser struct { +} + +var defaultAutoLinkParser = &autoLinkParser{} + +// NewAutoLinkParser returns a new InlineParser that parses autolinks +// surrounded by '<' and '>' . +func NewAutoLinkParser() InlineParser { + return defaultAutoLinkParser +} + +func (s *autoLinkParser) Trigger() []byte { + return []byte{'<'} +} + +func (s *autoLinkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node { + line, segment := block.PeekLine() + stop := util.FindEmailIndex(line[1:]) + typ := ast.AutoLinkType(ast.AutoLinkEmail) + if stop < 0 { + stop = util.FindURLIndex(line[1:]) + typ = ast.AutoLinkURL + } + if stop < 0 { + return nil + } + stop++ + if stop >= len(line) || line[stop] != '>' { + return nil + } + value := ast.NewTextSegment(text.NewSegment(segment.Start+1, segment.Start+stop)) + block.Advance(stop + 1) + return ast.NewAutoLink(typ, value) +} diff --git a/vendor/github.com/yuin/goldmark/parser/blockquote.go b/vendor/github.com/yuin/goldmark/parser/blockquote.go new file mode 100644 index 0000000000..e7778dca71 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/blockquote.go @@ -0,0 +1,69 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type blockquoteParser struct { +} + +var defaultBlockquoteParser = &blockquoteParser{} + +// NewBlockquoteParser returns a new BlockParser that +// parses blockquotes. +func NewBlockquoteParser() BlockParser { + return defaultBlockquoteParser +} + +func (b *blockquoteParser) process(reader text.Reader) bool { + line, _ := reader.PeekLine() + w, pos := util.IndentWidth(line, reader.LineOffset()) + if w > 3 || pos >= len(line) || line[pos] != '>' { + return false + } + pos++ + if pos >= len(line) || line[pos] == '\n' { + reader.Advance(pos) + return true + } + if line[pos] == ' ' || line[pos] == '\t' { + pos++ + } + reader.Advance(pos) + if line[pos-1] == '\t' { + reader.SetPadding(2) + } + return true +} + +func (b *blockquoteParser) Trigger() []byte { + return []byte{'>'} +} + +func (b *blockquoteParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + if b.process(reader) { + return ast.NewBlockquote(), HasChildren + } + return nil, NoChildren +} + +func (b *blockquoteParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + if b.process(reader) { + return Continue | HasChildren + } + return Close +} + +func (b *blockquoteParser) Close(node ast.Node, reader text.Reader, pc Context) { + // nothing to do +} + +func (b *blockquoteParser) CanInterruptParagraph() bool { + return true +} + +func (b *blockquoteParser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/parser/code_block.go b/vendor/github.com/yuin/goldmark/parser/code_block.go new file mode 100644 index 0000000000..c16ea413ab --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/code_block.go @@ -0,0 +1,96 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type codeBlockParser struct { +} + +// CodeBlockParser is a BlockParser implementation that parses indented code blocks. +var defaultCodeBlockParser = &codeBlockParser{} + +// NewCodeBlockParser returns a new BlockParser that +// parses code blocks. +func NewCodeBlockParser() BlockParser { + return defaultCodeBlockParser +} + +func (b *codeBlockParser) Trigger() []byte { + return nil +} + +func (b *codeBlockParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + line, segment := reader.PeekLine() + pos, padding := util.IndentPosition(line, reader.LineOffset(), 4) + if pos < 0 || util.IsBlank(line) { + return nil, NoChildren + } + node := ast.NewCodeBlock() + reader.AdvanceAndSetPadding(pos, padding) + _, segment = reader.PeekLine() + node.Lines().Append(segment) + reader.Advance(segment.Len() - 1) + return node, NoChildren + +} + +func (b *codeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + line, segment := reader.PeekLine() + if util.IsBlank(line) { + node.Lines().Append(segment.TrimLeftSpaceWidth(4, reader.Source())) + return Continue | NoChildren + } + pos, padding := util.IndentPosition(line, reader.LineOffset(), 4) + if pos < 0 { + return Close + } + reader.AdvanceAndSetPadding(pos, padding) + _, segment = reader.PeekLine() + + // if code block line starts with a tab, keep a tab as it is. + if segment.Padding != 0 { + preserveLeadingTabInCodeBlock(&segment, reader, 0) + } + + node.Lines().Append(segment) + reader.Advance(segment.Len() - 1) + return Continue | NoChildren +} + +func (b *codeBlockParser) Close(node ast.Node, reader text.Reader, pc Context) { + // trim trailing blank lines + lines := node.Lines() + length := lines.Len() - 1 + source := reader.Source() + for length >= 0 { + line := lines.At(length) + if util.IsBlank(line.Value(source)) { + length-- + } else { + break + } + } + lines.SetSliced(0, length+1) +} + +func (b *codeBlockParser) CanInterruptParagraph() bool { + return false +} + +func (b *codeBlockParser) CanAcceptIndentedLine() bool { + return true +} + +func preserveLeadingTabInCodeBlock(segment *text.Segment, reader text.Reader, indent int) { + offsetWithPadding := reader.LineOffset() + indent + sl, ss := reader.Position() + reader.SetPosition(sl, text.NewSegment(ss.Start-1, ss.Stop)) + if offsetWithPadding == reader.LineOffset() { + segment.Padding = 0 + segment.Start-- + } + reader.SetPosition(sl, ss) +} diff --git a/vendor/github.com/yuin/goldmark/parser/code_span.go b/vendor/github.com/yuin/goldmark/parser/code_span.go new file mode 100644 index 0000000000..13652367f5 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/code_span.go @@ -0,0 +1,83 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type codeSpanParser struct { +} + +var defaultCodeSpanParser = &codeSpanParser{} + +// NewCodeSpanParser return a new InlineParser that parses inline codes +// surrounded by '`' . +func NewCodeSpanParser() InlineParser { + return defaultCodeSpanParser +} + +func (s *codeSpanParser) Trigger() []byte { + return []byte{'`'} +} + +func (s *codeSpanParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node { + line, startSegment := block.PeekLine() + opener := 0 + for ; opener < len(line) && line[opener] == '`'; opener++ { + } + block.Advance(opener) + l, pos := block.Position() + node := ast.NewCodeSpan() + for { + line, segment := block.PeekLine() + if line == nil { + block.SetPosition(l, pos) + return ast.NewTextSegment(startSegment.WithStop(startSegment.Start + opener)) + } + for i := 0; i < len(line); i++ { + c := line[i] + if c == '`' { + oldi := i + for ; i < len(line) && line[i] == '`'; i++ { + } + closure := i - oldi + if closure == opener && (i >= len(line) || line[i] != '`') { + segment = segment.WithStop(segment.Start + i - closure) + if !segment.IsEmpty() { + node.AppendChild(node, ast.NewRawTextSegment(segment)) + } + block.Advance(i) + goto end + } + } + } + if !util.IsBlank(line) { + node.AppendChild(node, ast.NewRawTextSegment(segment)) + } + block.AdvanceLine() + } +end: + if !node.IsBlank(block.Source()) { + // trim first halfspace and last halfspace + segment := node.FirstChild().(*ast.Text).Segment + shouldTrimmed := true + if !(!segment.IsEmpty() && block.Source()[segment.Start] == ' ') { + shouldTrimmed = false + } + segment = node.LastChild().(*ast.Text).Segment + if !(!segment.IsEmpty() && block.Source()[segment.Stop-1] == ' ') { + shouldTrimmed = false + } + if shouldTrimmed { + t := node.FirstChild().(*ast.Text) + segment := t.Segment + t.Segment = segment.WithStart(segment.Start + 1) + t = node.LastChild().(*ast.Text) + segment = node.LastChild().(*ast.Text).Segment + t.Segment = segment.WithStop(segment.Stop - 1) + } + + } + return node +} diff --git a/vendor/github.com/yuin/goldmark/parser/delimiter.go b/vendor/github.com/yuin/goldmark/parser/delimiter.go new file mode 100644 index 0000000000..8259f62249 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/delimiter.go @@ -0,0 +1,241 @@ +package parser + +import ( + "fmt" + "strings" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +// A DelimiterProcessor interface provides a set of functions about +// Delimiter nodes. +type DelimiterProcessor interface { + // IsDelimiter returns true if given character is a delimiter, otherwise false. + IsDelimiter(byte) bool + + // CanOpenCloser returns true if given opener can close given closer, otherwise false. + CanOpenCloser(opener, closer *Delimiter) bool + + // OnMatch will be called when new matched delimiter found. + // OnMatch should return a new Node correspond to the matched delimiter. + OnMatch(consumes int) ast.Node +} + +// A Delimiter struct represents a delimiter like '*' of the Markdown text. +type Delimiter struct { + ast.BaseInline + + Segment text.Segment + + // CanOpen is set true if this delimiter can open a span for a new node. + // See https://spec.commonmark.org/0.29/#can-open-emphasis for details. + CanOpen bool + + // CanClose is set true if this delimiter can close a span for a new node. + // See https://spec.commonmark.org/0.29/#can-open-emphasis for details. + CanClose bool + + // Length is a remaining length of this delimiter. + Length int + + // OriginalLength is a original length of this delimiter. + OriginalLength int + + // Char is a character of this delimiter. + Char byte + + // PreviousDelimiter is a previous sibling delimiter node of this delimiter. + PreviousDelimiter *Delimiter + + // NextDelimiter is a next sibling delimiter node of this delimiter. + NextDelimiter *Delimiter + + // Processor is a DelimiterProcessor associated with this delimiter. + Processor DelimiterProcessor +} + +// Inline implements Inline.Inline. +func (d *Delimiter) Inline() {} + +// Dump implements Node.Dump. +func (d *Delimiter) Dump(source []byte, level int) { + fmt.Printf("%sDelimiter: \"%s\"\n", strings.Repeat(" ", level), string(d.Text(source))) +} + +var kindDelimiter = ast.NewNodeKind("Delimiter") + +// Kind implements Node.Kind +func (d *Delimiter) Kind() ast.NodeKind { + return kindDelimiter +} + +// Text implements Node.Text +func (d *Delimiter) Text(source []byte) []byte { + return d.Segment.Value(source) +} + +// ConsumeCharacters consumes delimiters. +func (d *Delimiter) ConsumeCharacters(n int) { + d.Length -= n + d.Segment = d.Segment.WithStop(d.Segment.Start + d.Length) +} + +// CalcComsumption calculates how many characters should be used for opening +// a new span correspond to given closer. +func (d *Delimiter) CalcComsumption(closer *Delimiter) int { + if (d.CanClose || closer.CanOpen) && (d.OriginalLength+closer.OriginalLength)%3 == 0 && closer.OriginalLength%3 != 0 { + return 0 + } + if d.Length >= 2 && closer.Length >= 2 { + return 2 + } + return 1 +} + +// NewDelimiter returns a new Delimiter node. +func NewDelimiter(canOpen, canClose bool, length int, char byte, processor DelimiterProcessor) *Delimiter { + c := &Delimiter{ + BaseInline: ast.BaseInline{}, + CanOpen: canOpen, + CanClose: canClose, + Length: length, + OriginalLength: length, + Char: char, + PreviousDelimiter: nil, + NextDelimiter: nil, + Processor: processor, + } + return c +} + +// ScanDelimiter scans a delimiter by given DelimiterProcessor. +func ScanDelimiter(line []byte, before rune, min int, processor DelimiterProcessor) *Delimiter { + i := 0 + c := line[i] + j := i + if !processor.IsDelimiter(c) { + return nil + } + for ; j < len(line) && c == line[j]; j++ { + } + if (j - i) >= min { + after := rune(' ') + if j != len(line) { + after = util.ToRune(line, j) + } + + canOpen, canClose := false, false + beforeIsPunctuation := util.IsPunctRune(before) + beforeIsWhitespace := util.IsSpaceRune(before) + afterIsPunctuation := util.IsPunctRune(after) + afterIsWhitespace := util.IsSpaceRune(after) + + isLeft := !afterIsWhitespace && + (!afterIsPunctuation || beforeIsWhitespace || beforeIsPunctuation) + isRight := !beforeIsWhitespace && + (!beforeIsPunctuation || afterIsWhitespace || afterIsPunctuation) + + if line[i] == '_' { + canOpen = isLeft && (!isRight || beforeIsPunctuation) + canClose = isRight && (!isLeft || afterIsPunctuation) + } else { + canOpen = isLeft + canClose = isRight + } + return NewDelimiter(canOpen, canClose, j-i, c, processor) + } + return nil +} + +// ProcessDelimiters processes the delimiter list in the context. +// Processing will be stop when reaching the bottom. +// +// If you implement an inline parser that can have other inline nodes as +// children, you should call this function when nesting span has closed. +func ProcessDelimiters(bottom ast.Node, pc Context) { + lastDelimiter := pc.LastDelimiter() + if lastDelimiter == nil { + return + } + var closer *Delimiter + if bottom != nil { + if bottom != lastDelimiter { + for c := lastDelimiter.PreviousSibling(); c != nil; { + if d, ok := c.(*Delimiter); ok { + closer = d + } + prev := c.PreviousSibling() + if prev == bottom { + break + } + c = prev + } + } + } else { + closer = pc.FirstDelimiter() + } + if closer == nil { + pc.ClearDelimiters(bottom) + return + } + for closer != nil { + if !closer.CanClose { + closer = closer.NextDelimiter + continue + } + consume := 0 + found := false + maybeOpener := false + var opener *Delimiter + for opener = closer.PreviousDelimiter; opener != nil; opener = opener.PreviousDelimiter { + if opener.CanOpen && opener.Processor.CanOpenCloser(opener, closer) { + maybeOpener = true + consume = opener.CalcComsumption(closer) + if consume > 0 { + found = true + break + } + } + } + if !found { + if !maybeOpener && !closer.CanOpen { + pc.RemoveDelimiter(closer) + } + closer = closer.NextDelimiter + continue + } + opener.ConsumeCharacters(consume) + closer.ConsumeCharacters(consume) + + node := opener.Processor.OnMatch(consume) + + parent := opener.Parent() + child := opener.NextSibling() + + for child != nil && child != closer { + next := child.NextSibling() + node.AppendChild(node, child) + child = next + } + parent.InsertAfter(parent, opener, node) + + for c := opener.NextDelimiter; c != nil && c != closer; { + next := c.NextDelimiter + pc.RemoveDelimiter(c) + c = next + } + + if opener.Length == 0 { + pc.RemoveDelimiter(opener) + } + + if closer.Length == 0 { + next := closer.NextDelimiter + pc.RemoveDelimiter(closer) + closer = next + } + } + pc.ClearDelimiters(bottom) +} diff --git a/vendor/github.com/yuin/goldmark/parser/emphasis.go b/vendor/github.com/yuin/goldmark/parser/emphasis.go new file mode 100644 index 0000000000..488647117c --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/emphasis.go @@ -0,0 +1,50 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" +) + +type emphasisDelimiterProcessor struct { +} + +func (p *emphasisDelimiterProcessor) IsDelimiter(b byte) bool { + return b == '*' || b == '_' +} + +func (p *emphasisDelimiterProcessor) CanOpenCloser(opener, closer *Delimiter) bool { + return opener.Char == closer.Char +} + +func (p *emphasisDelimiterProcessor) OnMatch(consumes int) ast.Node { + return ast.NewEmphasis(consumes) +} + +var defaultEmphasisDelimiterProcessor = &emphasisDelimiterProcessor{} + +type emphasisParser struct { +} + +var defaultEmphasisParser = &emphasisParser{} + +// NewEmphasisParser return a new InlineParser that parses emphasises. +func NewEmphasisParser() InlineParser { + return defaultEmphasisParser +} + +func (s *emphasisParser) Trigger() []byte { + return []byte{'*', '_'} +} + +func (s *emphasisParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node { + before := block.PrecendingCharacter() + line, segment := block.PeekLine() + node := ScanDelimiter(line, before, 1, defaultEmphasisDelimiterProcessor) + if node == nil { + return nil + } + node.Segment = segment.WithStop(segment.Start + node.OriginalLength) + block.Advance(node.OriginalLength) + pc.PushDelimiter(node) + return node +} diff --git a/vendor/github.com/yuin/goldmark/parser/fcode_block.go b/vendor/github.com/yuin/goldmark/parser/fcode_block.go new file mode 100644 index 0000000000..63c2fd46be --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/fcode_block.go @@ -0,0 +1,115 @@ +package parser + +import ( + "bytes" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type fencedCodeBlockParser struct { +} + +var defaultFencedCodeBlockParser = &fencedCodeBlockParser{} + +// NewFencedCodeBlockParser returns a new BlockParser that +// parses fenced code blocks. +func NewFencedCodeBlockParser() BlockParser { + return defaultFencedCodeBlockParser +} + +type fenceData struct { + char byte + indent int + length int + node ast.Node +} + +var fencedCodeBlockInfoKey = NewContextKey() + +func (b *fencedCodeBlockParser) Trigger() []byte { + return []byte{'~', '`'} +} + +func (b *fencedCodeBlockParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + line, segment := reader.PeekLine() + pos := pc.BlockOffset() + if pos < 0 || (line[pos] != '`' && line[pos] != '~') { + return nil, NoChildren + } + findent := pos + fenceChar := line[pos] + i := pos + for ; i < len(line) && line[i] == fenceChar; i++ { + } + oFenceLength := i - pos + if oFenceLength < 3 { + return nil, NoChildren + } + var info *ast.Text + if i < len(line)-1 { + rest := line[i:] + left := util.TrimLeftSpaceLength(rest) + right := util.TrimRightSpaceLength(rest) + if left < len(rest)-right { + infoStart, infoStop := segment.Start-segment.Padding+i+left, segment.Stop-right + value := rest[left : len(rest)-right] + if fenceChar == '`' && bytes.IndexByte(value, '`') > -1 { + return nil, NoChildren + } else if infoStart != infoStop { + info = ast.NewTextSegment(text.NewSegment(infoStart, infoStop)) + } + } + } + node := ast.NewFencedCodeBlock(info) + pc.Set(fencedCodeBlockInfoKey, &fenceData{fenceChar, findent, oFenceLength, node}) + return node, NoChildren + +} + +func (b *fencedCodeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + line, segment := reader.PeekLine() + fdata := pc.Get(fencedCodeBlockInfoKey).(*fenceData) + + // if code block line starts with a tab, keep a tab as it is. + if segment.Padding != 0 { + preserveLeadingTabInCodeBlock(&segment, reader, fdata.indent) + } + w, pos := util.IndentWidth(line, reader.LineOffset()) + if w < 4 { + i := pos + for ; i < len(line) && line[i] == fdata.char; i++ { + } + length := i - pos + if length >= fdata.length && util.IsBlank(line[i:]) { + newline := 1 + if line[len(line)-1] != '\n' { + newline = 0 + } + reader.Advance(segment.Stop - segment.Start - newline - segment.Padding) + return Close + } + } + pos, padding := util.DedentPositionPadding(line, reader.LineOffset(), segment.Padding, fdata.indent) + + seg := text.NewSegmentPadding(segment.Start+pos, segment.Stop, padding) + node.Lines().Append(seg) + reader.AdvanceAndSetPadding(segment.Stop-segment.Start-pos-1, padding) + return Continue | NoChildren +} + +func (b *fencedCodeBlockParser) Close(node ast.Node, reader text.Reader, pc Context) { + fdata := pc.Get(fencedCodeBlockInfoKey).(*fenceData) + if fdata.node == node { + pc.Set(fencedCodeBlockInfoKey, nil) + } +} + +func (b *fencedCodeBlockParser) CanInterruptParagraph() bool { + return true +} + +func (b *fencedCodeBlockParser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/parser/html_block.go b/vendor/github.com/yuin/goldmark/parser/html_block.go new file mode 100644 index 0000000000..845c00f982 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/html_block.go @@ -0,0 +1,228 @@ +package parser + +import ( + "bytes" + "regexp" + "strings" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var allowedBlockTags = map[string]bool{ + "address": true, + "article": true, + "aside": true, + "base": true, + "basefont": true, + "blockquote": true, + "body": true, + "caption": true, + "center": true, + "col": true, + "colgroup": true, + "dd": true, + "details": true, + "dialog": true, + "dir": true, + "div": true, + "dl": true, + "dt": true, + "fieldset": true, + "figcaption": true, + "figure": true, + "footer": true, + "form": true, + "frame": true, + "frameset": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "header": true, + "hr": true, + "html": true, + "iframe": true, + "legend": true, + "li": true, + "link": true, + "main": true, + "menu": true, + "menuitem": true, + "meta": true, + "nav": true, + "noframes": true, + "ol": true, + "optgroup": true, + "option": true, + "p": true, + "param": true, + "section": true, + "source": true, + "summary": true, + "table": true, + "tbody": true, + "td": true, + "tfoot": true, + "th": true, + "thead": true, + "title": true, + "tr": true, + "track": true, + "ul": true, +} + +var htmlBlockType1OpenRegexp = regexp.MustCompile(`(?i)^[ ]{0,3}<(script|pre|style)(?:\s.*|>.*|/>.*|)\n?$`) +var htmlBlockType1CloseRegexp = regexp.MustCompile(`(?i)^.*.*`) + +var htmlBlockType2OpenRegexp = regexp.MustCompile(`^[ ]{0,3}'} + +var htmlBlockType3OpenRegexp = regexp.MustCompile(`^[ ]{0,3}<\?`) +var htmlBlockType3Close = []byte{'?', '>'} + +var htmlBlockType4OpenRegexp = regexp.MustCompile(`^[ ]{0,3}'} + +var htmlBlockType5OpenRegexp = regexp.MustCompile(`^[ ]{0,3}<\!\[CDATA\[`) +var htmlBlockType5Close = []byte{']', ']', '>'} + +var htmlBlockType6Regexp = regexp.MustCompile(`^[ ]{0,3}.*|/>.*|)\n?$`) + +var htmlBlockType7Regexp = regexp.MustCompile(`^[ ]{0,3}<(/)?([a-zA-Z0-9\-]+)(` + attributePattern + `*)(:?>|/>)\s*\n?$`) + +type htmlBlockParser struct { +} + +var defaultHTMLBlockParser = &htmlBlockParser{} + +// NewHTMLBlockParser return a new BlockParser that can parse html +// blocks. +func NewHTMLBlockParser() BlockParser { + return defaultHTMLBlockParser +} + +func (b *htmlBlockParser) Trigger() []byte { + return []byte{'<'} +} + +func (b *htmlBlockParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + var node *ast.HTMLBlock + line, segment := reader.PeekLine() + last := pc.LastOpenedBlock().Node + if pos := pc.BlockOffset(); pos < 0 || line[pos] != '<' { + return nil, NoChildren + } + + if m := htmlBlockType1OpenRegexp.FindSubmatchIndex(line); m != nil { + node = ast.NewHTMLBlock(ast.HTMLBlockType1) + } else if htmlBlockType2OpenRegexp.Match(line) { + node = ast.NewHTMLBlock(ast.HTMLBlockType2) + } else if htmlBlockType3OpenRegexp.Match(line) { + node = ast.NewHTMLBlock(ast.HTMLBlockType3) + } else if htmlBlockType4OpenRegexp.Match(line) { + node = ast.NewHTMLBlock(ast.HTMLBlockType4) + } else if htmlBlockType5OpenRegexp.Match(line) { + node = ast.NewHTMLBlock(ast.HTMLBlockType5) + } else if match := htmlBlockType7Regexp.FindSubmatchIndex(line); match != nil { + isCloseTag := match[2] > -1 && bytes.Equal(line[match[2]:match[3]], []byte("/")) + hasAttr := match[6] != match[7] + tagName := strings.ToLower(string(line[match[4]:match[5]])) + _, ok := allowedBlockTags[tagName] + if ok { + node = ast.NewHTMLBlock(ast.HTMLBlockType6) + } else if tagName != "script" && tagName != "style" && tagName != "pre" && !ast.IsParagraph(last) && !(isCloseTag && hasAttr) { // type 7 can not interrupt paragraph + node = ast.NewHTMLBlock(ast.HTMLBlockType7) + } + } + if node == nil { + if match := htmlBlockType6Regexp.FindSubmatchIndex(line); match != nil { + tagName := string(line[match[2]:match[3]]) + _, ok := allowedBlockTags[strings.ToLower(tagName)] + if ok { + node = ast.NewHTMLBlock(ast.HTMLBlockType6) + } + } + } + if node != nil { + reader.Advance(segment.Len() - 1) + node.Lines().Append(segment) + return node, NoChildren + } + return nil, NoChildren +} + +func (b *htmlBlockParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + htmlBlock := node.(*ast.HTMLBlock) + lines := htmlBlock.Lines() + line, segment := reader.PeekLine() + var closurePattern []byte + + switch htmlBlock.HTMLBlockType { + case ast.HTMLBlockType1: + if lines.Len() == 1 { + firstLine := lines.At(0) + if htmlBlockType1CloseRegexp.Match(firstLine.Value(reader.Source())) { + return Close + } + } + if htmlBlockType1CloseRegexp.Match(line) { + htmlBlock.ClosureLine = segment + reader.Advance(segment.Len() - 1) + return Close + } + case ast.HTMLBlockType2: + closurePattern = htmlBlockType2Close + fallthrough + case ast.HTMLBlockType3: + if closurePattern == nil { + closurePattern = htmlBlockType3Close + } + fallthrough + case ast.HTMLBlockType4: + if closurePattern == nil { + closurePattern = htmlBlockType4Close + } + fallthrough + case ast.HTMLBlockType5: + if closurePattern == nil { + closurePattern = htmlBlockType5Close + } + + if lines.Len() == 1 { + firstLine := lines.At(0) + if bytes.Contains(firstLine.Value(reader.Source()), closurePattern) { + return Close + } + } + if bytes.Contains(line, closurePattern) { + htmlBlock.ClosureLine = segment + reader.Advance(segment.Len() - 1) + return Close + } + + case ast.HTMLBlockType6, ast.HTMLBlockType7: + if util.IsBlank(line) { + return Close + } + } + node.Lines().Append(segment) + reader.Advance(segment.Len() - 1) + return Continue | NoChildren +} + +func (b *htmlBlockParser) Close(node ast.Node, reader text.Reader, pc Context) { + // nothing to do +} + +func (b *htmlBlockParser) CanInterruptParagraph() bool { + return true +} + +func (b *htmlBlockParser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/parser/link.go b/vendor/github.com/yuin/goldmark/parser/link.go new file mode 100644 index 0000000000..c36cce5d90 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/link.go @@ -0,0 +1,379 @@ +package parser + +import ( + "fmt" + "strings" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var linkLabelStateKey = NewContextKey() + +type linkLabelState struct { + ast.BaseInline + + Segment text.Segment + + IsImage bool + + Prev *linkLabelState + + Next *linkLabelState + + First *linkLabelState + + Last *linkLabelState +} + +func newLinkLabelState(segment text.Segment, isImage bool) *linkLabelState { + return &linkLabelState{ + Segment: segment, + IsImage: isImage, + } +} + +func (s *linkLabelState) Text(source []byte) []byte { + return s.Segment.Value(source) +} + +func (s *linkLabelState) Dump(source []byte, level int) { + fmt.Printf("%slinkLabelState: \"%s\"\n", strings.Repeat(" ", level), s.Text(source)) +} + +var kindLinkLabelState = ast.NewNodeKind("LinkLabelState") + +func (s *linkLabelState) Kind() ast.NodeKind { + return kindLinkLabelState +} + +func pushLinkLabelState(pc Context, v *linkLabelState) { + tlist := pc.Get(linkLabelStateKey) + var list *linkLabelState + if tlist == nil { + list = v + v.First = v + v.Last = v + pc.Set(linkLabelStateKey, list) + } else { + list = tlist.(*linkLabelState) + l := list.Last + list.Last = v + l.Next = v + v.Prev = l + } +} + +func removeLinkLabelState(pc Context, d *linkLabelState) { + tlist := pc.Get(linkLabelStateKey) + var list *linkLabelState + if tlist == nil { + return + } + list = tlist.(*linkLabelState) + + if d.Prev == nil { + list = d.Next + if list != nil { + list.First = d + list.Last = d.Last + list.Prev = nil + pc.Set(linkLabelStateKey, list) + } else { + pc.Set(linkLabelStateKey, nil) + } + } else { + d.Prev.Next = d.Next + if d.Next != nil { + d.Next.Prev = d.Prev + } + } + if list != nil && d.Next == nil { + list.Last = d.Prev + } + d.Next = nil + d.Prev = nil + d.First = nil + d.Last = nil +} + +type linkParser struct { +} + +var defaultLinkParser = &linkParser{} + +// NewLinkParser return a new InlineParser that parses links. +func NewLinkParser() InlineParser { + return defaultLinkParser +} + +func (s *linkParser) Trigger() []byte { + return []byte{'!', '[', ']'} +} + +var linkBottom = NewContextKey() + +func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node { + line, segment := block.PeekLine() + if line[0] == '!' { + if len(line) > 1 && line[1] == '[' { + block.Advance(1) + pc.Set(linkBottom, pc.LastDelimiter()) + return processLinkLabelOpen(block, segment.Start+1, true, pc) + } + return nil + } + if line[0] == '[' { + pc.Set(linkBottom, pc.LastDelimiter()) + return processLinkLabelOpen(block, segment.Start, false, pc) + } + + // line[0] == ']' + tlist := pc.Get(linkLabelStateKey) + if tlist == nil { + return nil + } + last := tlist.(*linkLabelState).Last + if last == nil { + return nil + } + block.Advance(1) + removeLinkLabelState(pc, last) + if s.containsLink(last) { // a link in a link text is not allowed + ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment) + return nil + } + + c := block.Peek() + l, pos := block.Position() + var link *ast.Link + var hasValue bool + if c == '(' { // normal link + link = s.parseLink(parent, last, block, pc) + } else if c == '[' { // reference link + link, hasValue = s.parseReferenceLink(parent, last, block, pc) + if link == nil && hasValue { + ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment) + return nil + } + } + + if link == nil { + // maybe shortcut reference link + block.SetPosition(l, pos) + ssegment := text.NewSegment(last.Segment.Stop, segment.Start) + maybeReference := block.Value(ssegment) + ref, ok := pc.Reference(util.ToLinkReference(maybeReference)) + if !ok { + ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment) + return nil + } + link = ast.NewLink() + s.processLinkLabel(parent, link, last, pc) + link.Title = ref.Title() + link.Destination = ref.Destination() + } + if last.IsImage { + last.Parent().RemoveChild(last.Parent(), last) + return ast.NewImage(link) + } + last.Parent().RemoveChild(last.Parent(), last) + return link +} + +func (s *linkParser) containsLink(last *linkLabelState) bool { + if last.IsImage { + return false + } + var c ast.Node + for c = last; c != nil; c = c.NextSibling() { + if _, ok := c.(*ast.Link); ok { + return true + } + } + return false +} + +func processLinkLabelOpen(block text.Reader, pos int, isImage bool, pc Context) *linkLabelState { + start := pos + if isImage { + start-- + } + state := newLinkLabelState(text.NewSegment(start, pos+1), isImage) + pushLinkLabelState(pc, state) + block.Advance(1) + return state +} + +func (s *linkParser) processLinkLabel(parent ast.Node, link *ast.Link, last *linkLabelState, pc Context) { + var bottom ast.Node + if v := pc.Get(linkBottom); v != nil { + bottom = v.(ast.Node) + } + pc.Set(linkBottom, nil) + ProcessDelimiters(bottom, pc) + for c := last.NextSibling(); c != nil; { + next := c.NextSibling() + parent.RemoveChild(parent, c) + link.AppendChild(link, c) + c = next + } +} + +func (s *linkParser) parseReferenceLink(parent ast.Node, last *linkLabelState, block text.Reader, pc Context) (*ast.Link, bool) { + _, orgpos := block.Position() + block.Advance(1) // skip '[' + line, segment := block.PeekLine() + endIndex := util.FindClosure(line, '[', ']', false, true) + if endIndex < 0 { + return nil, false + } + + block.Advance(endIndex + 1) + ssegment := segment.WithStop(segment.Start + endIndex) + maybeReference := block.Value(ssegment) + if util.IsBlank(maybeReference) { // collapsed reference link + ssegment = text.NewSegment(last.Segment.Stop, orgpos.Start-1) + maybeReference = block.Value(ssegment) + } + + ref, ok := pc.Reference(util.ToLinkReference(maybeReference)) + if !ok { + return nil, true + } + + link := ast.NewLink() + s.processLinkLabel(parent, link, last, pc) + link.Title = ref.Title() + link.Destination = ref.Destination() + return link, true +} + +func (s *linkParser) parseLink(parent ast.Node, last *linkLabelState, block text.Reader, pc Context) *ast.Link { + block.Advance(1) // skip '(' + block.SkipSpaces() + var title []byte + var destination []byte + var ok bool + if block.Peek() == ')' { // empty link like '[link]()' + block.Advance(1) + } else { + destination, ok = parseLinkDestination(block) + if !ok { + return nil + } + block.SkipSpaces() + if block.Peek() == ')' { + block.Advance(1) + } else { + title, ok = parseLinkTitle(block) + if !ok { + return nil + } + block.SkipSpaces() + if block.Peek() == ')' { + block.Advance(1) + } else { + return nil + } + } + } + + link := ast.NewLink() + s.processLinkLabel(parent, link, last, pc) + link.Destination = destination + link.Title = title + return link +} + +func parseLinkDestination(block text.Reader) ([]byte, bool) { + block.SkipSpaces() + line, _ := block.PeekLine() + if block.Peek() == '<' { + i := 1 + for i < len(line) { + c := line[i] + if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) { + i += 2 + continue + } else if c == '>' { + block.Advance(i + 1) + return line[1:i], true + } + i++ + } + return nil, false + } + opened := 0 + i := 0 + for i < len(line) { + c := line[i] + if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) { + i += 2 + continue + } else if c == '(' { + opened++ + } else if c == ')' { + opened-- + if opened < 0 { + break + } + } else if util.IsSpace(c) { + break + } + i++ + } + block.Advance(i) + return line[:i], len(line[:i]) != 0 +} + +func parseLinkTitle(block text.Reader) ([]byte, bool) { + block.SkipSpaces() + opener := block.Peek() + if opener != '"' && opener != '\'' && opener != '(' { + return nil, false + } + closer := opener + if opener == '(' { + closer = ')' + } + savedLine, savedPosition := block.Position() + var title []byte + for i := 0; ; i++ { + line, _ := block.PeekLine() + if line == nil { + block.SetPosition(savedLine, savedPosition) + return nil, false + } + offset := 0 + if i == 0 { + offset = 1 + } + pos := util.FindClosure(line[offset:], opener, closer, false, true) + if pos < 0 { + title = append(title, line[offset:]...) + block.AdvanceLine() + continue + } + pos += offset + 1 // 1: closer + block.Advance(pos) + if i == 0 { // avoid allocating new slice + return line[offset : pos-1], true + } + return append(title, line[offset:pos-1]...), true + } +} + +func (s *linkParser) CloseBlock(parent ast.Node, block text.Reader, pc Context) { + tlist := pc.Get(linkLabelStateKey) + if tlist == nil { + return + } + for s := tlist.(*linkLabelState); s != nil; { + next := s.Next + removeLinkLabelState(pc, s) + s.Parent().ReplaceChild(s.Parent(), s, ast.NewTextSegment(s.Segment)) + s = next + } +} diff --git a/vendor/github.com/yuin/goldmark/parser/link_ref.go b/vendor/github.com/yuin/goldmark/parser/link_ref.go new file mode 100644 index 0000000000..3fa1ecf6fa --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/link_ref.go @@ -0,0 +1,163 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type linkReferenceParagraphTransformer struct { +} + +// LinkReferenceParagraphTransformer is a ParagraphTransformer implementation +// that parses and extracts link reference from paragraphs. +var LinkReferenceParagraphTransformer = &linkReferenceParagraphTransformer{} + +func (p *linkReferenceParagraphTransformer) Transform(node *ast.Paragraph, reader text.Reader, pc Context) { + lines := node.Lines() + block := text.NewBlockReader(reader.Source(), lines) + removes := [][2]int{} + for { + start, end := parseLinkReferenceDefinition(block, pc) + if start > -1 { + if start == end { + end++ + } + removes = append(removes, [2]int{start, end}) + continue + } + break + } + + offset := 0 + for _, remove := range removes { + if lines.Len() == 0 { + break + } + s := lines.Sliced(remove[1]-offset, lines.Len()) + lines.SetSliced(0, remove[0]-offset) + lines.AppendAll(s) + offset = remove[1] + } + + if lines.Len() == 0 { + t := ast.NewTextBlock() + t.SetBlankPreviousLines(node.HasBlankPreviousLines()) + node.Parent().ReplaceChild(node.Parent(), node, t) + return + } + + node.SetLines(lines) +} + +func parseLinkReferenceDefinition(block text.Reader, pc Context) (int, int) { + block.SkipSpaces() + line, segment := block.PeekLine() + if line == nil { + return -1, -1 + } + startLine, _ := block.Position() + width, pos := util.IndentWidth(line, 0) + if width > 3 { + return -1, -1 + } + if width != 0 { + pos++ + } + if line[pos] != '[' { + return -1, -1 + } + open := segment.Start + pos + 1 + closes := -1 + block.Advance(pos + 1) + for { + line, segment = block.PeekLine() + if line == nil { + return -1, -1 + } + closure := util.FindClosure(line, '[', ']', false, false) + if closure > -1 { + closes = segment.Start + closure + next := closure + 1 + if next >= len(line) || line[next] != ':' { + return -1, -1 + } + block.Advance(next + 1) + break + } + block.AdvanceLine() + } + if closes < 0 { + return -1, -1 + } + label := block.Value(text.NewSegment(open, closes)) + if util.IsBlank(label) { + return -1, -1 + } + block.SkipSpaces() + destination, ok := parseLinkDestination(block) + if !ok { + return -1, -1 + } + line, segment = block.PeekLine() + isNewLine := line == nil || util.IsBlank(line) + + endLine, _ := block.Position() + _, spaces, _ := block.SkipSpaces() + opener := block.Peek() + if opener != '"' && opener != '\'' && opener != '(' { + if !isNewLine { + return -1, -1 + } + ref := NewReference(label, destination, nil) + pc.AddReference(ref) + return startLine, endLine + 1 + } + if spaces == 0 { + return -1, -1 + } + block.Advance(1) + open = -1 + closes = -1 + closer := opener + if opener == '(' { + closer = ')' + } + for { + line, segment = block.PeekLine() + if line == nil { + return -1, -1 + } + if open < 0 { + open = segment.Start + } + closure := util.FindClosure(line, opener, closer, false, true) + if closure > -1 { + closes = segment.Start + closure + block.Advance(closure + 1) + break + } + block.AdvanceLine() + } + if closes < 0 { + return -1, -1 + } + + line, segment = block.PeekLine() + if line != nil && !util.IsBlank(line) { + if !isNewLine { + return -1, -1 + } + title := block.Value(text.NewSegment(open, closes)) + ref := NewReference(label, destination, title) + pc.AddReference(ref) + return startLine, endLine + } + + title := block.Value(text.NewSegment(open, closes)) + + endLine, _ = block.Position() + ref := NewReference(label, destination, title) + pc.AddReference(ref) + return startLine, endLine + 1 +} diff --git a/vendor/github.com/yuin/goldmark/parser/list.go b/vendor/github.com/yuin/goldmark/parser/list.go new file mode 100644 index 0000000000..44602828ec --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/list.go @@ -0,0 +1,253 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" + "strconv" +) + +type listItemType int + +const ( + notList listItemType = iota + bulletList + orderedList +) + +// Same as +// `^(([ ]*)([\-\*\+]))(\s+.*)?\n?$`.FindSubmatchIndex or +// `^(([ ]*)(\d{1,9}[\.\)]))(\s+.*)?\n?$`.FindSubmatchIndex +func parseListItem(line []byte) ([6]int, listItemType) { + i := 0 + l := len(line) + ret := [6]int{} + for ; i < l && line[i] == ' '; i++ { + c := line[i] + if c == '\t' { + return ret, notList + } + } + if i > 3 { + return ret, notList + } + ret[0] = 0 + ret[1] = i + ret[2] = i + var typ listItemType + if i < l && (line[i] == '-' || line[i] == '*' || line[i] == '+') { + i++ + ret[3] = i + typ = bulletList + } else if i < l { + for ; i < l && util.IsNumeric(line[i]); i++ { + } + ret[3] = i + if ret[3] == ret[2] || ret[3]-ret[2] > 9 { + return ret, notList + } + if i < l && (line[i] == '.' || line[i] == ')') { + i++ + ret[3] = i + } else { + return ret, notList + } + typ = orderedList + } else { + return ret, notList + } + if i < l && line[i] != '\n' { + w, _ := util.IndentWidth(line[i:], 0) + if w == 0 { + return ret, notList + } + } + if i >= l { + ret[4] = -1 + ret[5] = -1 + return ret, typ + } + ret[4] = i + ret[5] = len(line) + if line[ret[5]-1] == '\n' && line[i] != '\n' { + ret[5]-- + } + return ret, typ +} + +func matchesListItem(source []byte, strict bool) ([6]int, listItemType) { + m, typ := parseListItem(source) + if typ != notList && (!strict || strict && m[1] < 4) { + return m, typ + } + return m, notList +} + +func calcListOffset(source []byte, match [6]int) int { + offset := 0 + if match[4] < 0 || util.IsBlank(source[match[4]:]) { // list item starts with a blank line + offset = 1 + } else { + offset, _ = util.IndentWidth(source[match[4]:], match[4]) + if offset > 4 { // offseted codeblock + offset = 1 + } + } + return offset +} + +func lastOffset(node ast.Node) int { + lastChild := node.LastChild() + if lastChild != nil { + return lastChild.(*ast.ListItem).Offset + } + return 0 +} + +type listParser struct { +} + +var defaultListParser = &listParser{} + +// NewListParser returns a new BlockParser that +// parses lists. +// This parser must take precedence over the ListItemParser. +func NewListParser() BlockParser { + return defaultListParser +} + +func (b *listParser) Trigger() []byte { + return []byte{'-', '+', '*', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} +} + +func (b *listParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + last := pc.LastOpenedBlock().Node + if _, lok := last.(*ast.List); lok || pc.Get(skipListParser) != nil { + pc.Set(skipListParser, nil) + return nil, NoChildren + } + line, _ := reader.PeekLine() + match, typ := matchesListItem(line, true) + if typ == notList { + return nil, NoChildren + } + start := -1 + if typ == orderedList { + number := line[match[2] : match[3]-1] + start, _ = strconv.Atoi(string(number)) + } + + if ast.IsParagraph(last) && last.Parent() == parent { + // we allow only lists starting with 1 to interrupt paragraphs. + if typ == orderedList && start != 1 { + return nil, NoChildren + } + //an empty list item cannot interrupt a paragraph: + if match[5]-match[4] == 1 { + return nil, NoChildren + } + } + + marker := line[match[3]-1] + node := ast.NewList(marker) + if start > -1 { + node.Start = start + } + return node, HasChildren +} + +func (b *listParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + list := node.(*ast.List) + line, _ := reader.PeekLine() + if util.IsBlank(line) { + // A list item can begin with at most one blank line + if node.ChildCount() == 1 && node.LastChild().ChildCount() == 0 { + return Close + } + + reader.Advance(len(line)-1) + return Continue | HasChildren + } + + // "offset" means a width that bar indicates. + // - aaaaaaaa + // |----| + // + // If the indent is less than the last offset like + // - a + // - b <--- current line + // it maybe a new child of the list. + offset := lastOffset(node) + indent, _ := util.IndentWidth(line, reader.LineOffset()) + + if indent < offset { + if indent < 4 { + match, typ := matchesListItem(line, false) // may have a leading spaces more than 3 + if typ != notList && match[1]-offset < 4 { + marker := line[match[3]-1] + if !list.CanContinue(marker, typ == orderedList) { + return Close + } + // Thematic Breaks take precedence over lists + if isThematicBreak(line[match[3]-1:], 0) { + isHeading := false + last := pc.LastOpenedBlock().Node + if ast.IsParagraph(last) { + c, ok := matchesSetextHeadingBar(line[match[3]-1:]) + if ok && c == '-' { + isHeading = true + } + } + if !isHeading { + return Close + } + } + + return Continue | HasChildren + } + } + return Close + } + return Continue | HasChildren +} + +func (b *listParser) Close(node ast.Node, reader text.Reader, pc Context) { + list := node.(*ast.List) + + for c := node.FirstChild(); c != nil && list.IsTight; c = c.NextSibling() { + if c.FirstChild() != nil && c.FirstChild() != c.LastChild() { + for c1 := c.FirstChild().NextSibling(); c1 != nil; c1 = c1.NextSibling() { + if bl, ok := c1.(ast.Node); ok && bl.HasBlankPreviousLines() { + list.IsTight = false + break + } + } + } + if c != node.FirstChild() { + if bl, ok := c.(ast.Node); ok && bl.HasBlankPreviousLines() { + list.IsTight = false + } + } + } + + if list.IsTight { + for child := node.FirstChild(); child != nil; child = child.NextSibling() { + for gc := child.FirstChild(); gc != nil; gc = gc.NextSibling() { + paragraph, ok := gc.(*ast.Paragraph) + if ok { + textBlock := ast.NewTextBlock() + textBlock.SetLines(paragraph.Lines()) + child.ReplaceChild(child, paragraph, textBlock) + } + } + } + } +} + +func (b *listParser) CanInterruptParagraph() bool { + return true +} + +func (b *listParser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/parser/list_item.go b/vendor/github.com/yuin/goldmark/parser/list_item.go new file mode 100644 index 0000000000..6c8db95485 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/list_item.go @@ -0,0 +1,87 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type listItemParser struct { +} + +var defaultListItemParser = &listItemParser{} + +// NewListItemParser returns a new BlockParser that +// parses list items. +func NewListItemParser() BlockParser { + return defaultListItemParser +} + +var skipListParser = NewContextKey() +var skipListParserValue interface{} = true + +func (b *listItemParser) Trigger() []byte { + return []byte{'-', '+', '*', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} +} + +func (b *listItemParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + list, lok := parent.(*ast.List) + if !lok { // list item must be a child of a list + return nil, NoChildren + } + offset := lastOffset(list) + line, _ := reader.PeekLine() + match, typ := matchesListItem(line, false) + if typ == notList { + return nil, NoChildren + } + if match[1]-offset > 3 { + return nil, NoChildren + } + itemOffset := calcListOffset(line, match) + node := ast.NewListItem(match[3] + itemOffset) + if match[4] < 0 || match[5]-match[4] == 1 { + return node, NoChildren + } + + pos, padding := util.IndentPosition(line[match[4]:], match[4], itemOffset) + child := match[3] + pos + reader.AdvanceAndSetPadding(child, padding) + return node, HasChildren +} + +func (b *listItemParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + line, _ := reader.PeekLine() + if util.IsBlank(line) { + reader.Advance(len(line)-1) + + return Continue | HasChildren + } + + indent, _ := util.IndentWidth(line, reader.LineOffset()) + offset := lastOffset(node.Parent()) + if indent < offset && indent < 4 { + _, typ := matchesListItem(line, true) + // new list item found + if typ != notList { + pc.Set(skipListParser, skipListParserValue) + } + return Close + } + pos, padding := util.IndentPosition(line, reader.LineOffset(), offset) + reader.AdvanceAndSetPadding(pos, padding) + + return Continue | HasChildren +} + +func (b *listItemParser) Close(node ast.Node, reader text.Reader, pc Context) { + // nothing to do +} + +func (b *listItemParser) CanInterruptParagraph() bool { + return true +} + +func (b *listItemParser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/parser/paragraph.go b/vendor/github.com/yuin/goldmark/parser/paragraph.go new file mode 100644 index 0000000000..2dd2b9a97d --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/paragraph.go @@ -0,0 +1,71 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" +) + +type paragraphParser struct { +} + +var defaultParagraphParser = ¶graphParser{} + +// NewParagraphParser returns a new BlockParser that +// parses paragraphs. +func NewParagraphParser() BlockParser { + return defaultParagraphParser +} + +func (b *paragraphParser) Trigger() []byte { + return nil +} + +func (b *paragraphParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + _, segment := reader.PeekLine() + segment = segment.TrimLeftSpace(reader.Source()) + if segment.IsEmpty() { + return nil, NoChildren + } + node := ast.NewParagraph() + node.Lines().Append(segment) + reader.Advance(segment.Len() - 1) + return node, NoChildren +} + +func (b *paragraphParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + _, segment := reader.PeekLine() + segment = segment.TrimLeftSpace(reader.Source()) + if segment.IsEmpty() { + return Close + } + node.Lines().Append(segment) + reader.Advance(segment.Len() - 1) + return Continue | NoChildren +} + +func (b *paragraphParser) Close(node ast.Node, reader text.Reader, pc Context) { + parent := node.Parent() + if parent == nil { + // paragraph has been transformed + return + } + lines := node.Lines() + if lines.Len() != 0 { + // trim trailing spaces + length := lines.Len() + lastLine := node.Lines().At(length - 1) + node.Lines().Set(length-1, lastLine.TrimRightSpace(reader.Source())) + } + if lines.Len() == 0 { + node.Parent().RemoveChild(node.Parent(), node) + return + } +} + +func (b *paragraphParser) CanInterruptParagraph() bool { + return false +} + +func (b *paragraphParser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/parser/parser.go b/vendor/github.com/yuin/goldmark/parser/parser.go new file mode 100644 index 0000000000..6e0e935674 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/parser.go @@ -0,0 +1,1229 @@ +// Package parser contains stuff that are related to parsing a Markdown text. +package parser + +import ( + "fmt" + "strings" + "sync" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +// A Reference interface represents a link reference in Markdown text. +type Reference interface { + // String implements Stringer. + String() string + + // Label returns a label of the reference. + Label() []byte + + // Destination returns a destination(URL) of the reference. + Destination() []byte + + // Title returns a title of the reference. + Title() []byte +} + +type reference struct { + label []byte + destination []byte + title []byte +} + +// NewReference returns a new Reference. +func NewReference(label, destination, title []byte) Reference { + return &reference{label, destination, title} +} + +func (r *reference) Label() []byte { + return r.label +} + +func (r *reference) Destination() []byte { + return r.destination +} + +func (r *reference) Title() []byte { + return r.title +} + +func (r *reference) String() string { + return fmt.Sprintf("Reference{Label:%s, Destination:%s, Title:%s}", r.label, r.destination, r.title) +} + +// An IDs interface is a collection of the element ids. +type IDs interface { + // Generate generates a new element id. + Generate(value []byte, kind ast.NodeKind) []byte + + // Put puts a given element id to the used ids table. + Put(value []byte) +} + +type ids struct { + values map[string]bool +} + +func newIDs() IDs { + return &ids{ + values: map[string]bool{}, + } +} + +func (s *ids) Generate(value []byte, kind ast.NodeKind) []byte { + value = util.TrimLeftSpace(value) + value = util.TrimRightSpace(value) + result := []byte{} + for i := 0; i < len(value); { + v := value[i] + l := util.UTF8Len(v) + i += int(l) + if l != 1 { + continue + } + if util.IsAlphaNumeric(v) { + if 'A' <= v && v <= 'Z' { + v += 'a' - 'A' + } + result = append(result, v) + } else if util.IsSpace(v) || v == '-' || v == '_' { + result = append(result, '-') + } + } + if len(result) == 0 { + if kind == ast.KindHeading { + result = []byte("heading") + } else { + result = []byte("id") + } + } + if _, ok := s.values[util.BytesToReadOnlyString(result)]; !ok { + s.values[util.BytesToReadOnlyString(result)] = true + return result + } + for i := 1; ; i++ { + newResult := fmt.Sprintf("%s-%d", result, i) + if _, ok := s.values[newResult]; !ok { + s.values[newResult] = true + return []byte(newResult) + } + + } +} + +func (s *ids) Put(value []byte) { + s.values[util.BytesToReadOnlyString(value)] = true +} + +// ContextKey is a key that is used to set arbitrary values to the context. +type ContextKey int + +// ContextKeyMax is a maximum value of the ContextKey. +var ContextKeyMax ContextKey + +// NewContextKey return a new ContextKey value. +func NewContextKey() ContextKey { + ContextKeyMax++ + return ContextKeyMax +} + +// A Context interface holds a information that are necessary to parse +// Markdown text. +type Context interface { + // String implements Stringer. + String() string + + // Get returns a value associated with the given key. + Get(ContextKey) interface{} + + // ComputeIfAbsent computes a value if a value associated with the given key is absent and returns the value. + ComputeIfAbsent(ContextKey, func() interface{}) interface{} + + // Set sets the given value to the context. + Set(ContextKey, interface{}) + + // AddReference adds the given reference to this context. + AddReference(Reference) + + // Reference returns (a reference, true) if a reference associated with + // the given label exists, otherwise (nil, false). + Reference(label string) (Reference, bool) + + // References returns a list of references. + References() []Reference + + // IDs returns a collection of the element ids. + IDs() IDs + + // BlockOffset returns a first non-space character position on current line. + // This value is valid only for BlockParser.Open. + // BlockOffset returns -1 if current line is blank. + BlockOffset() int + + // BlockOffset sets a first non-space character position on current line. + // This value is valid only for BlockParser.Open. + SetBlockOffset(int) + + // BlockIndent returns an indent width on current line. + // This value is valid only for BlockParser.Open. + // BlockIndent returns -1 if current line is blank. + BlockIndent() int + + // BlockIndent sets an indent width on current line. + // This value is valid only for BlockParser.Open. + SetBlockIndent(int) + + // FirstDelimiter returns a first delimiter of the current delimiter list. + FirstDelimiter() *Delimiter + + // LastDelimiter returns a last delimiter of the current delimiter list. + LastDelimiter() *Delimiter + + // PushDelimiter appends the given delimiter to the tail of the current + // delimiter list. + PushDelimiter(delimiter *Delimiter) + + // RemoveDelimiter removes the given delimiter from the current delimiter list. + RemoveDelimiter(d *Delimiter) + + // ClearDelimiters clears the current delimiter list. + ClearDelimiters(bottom ast.Node) + + // OpenedBlocks returns a list of nodes that are currently in parsing. + OpenedBlocks() []Block + + // SetOpenedBlocks sets a list of nodes that are currently in parsing. + SetOpenedBlocks([]Block) + + // LastOpenedBlock returns a last node that is currently in parsing. + LastOpenedBlock() Block + + // IsInLinkLabel returns true if current position seems to be in link label. + IsInLinkLabel() bool +} + +// A ContextConfig struct is a data structure that holds configuration of the Context. +type ContextConfig struct { + IDs IDs +} + +// An ContextOption is a functional option type for the Context. +type ContextOption func(*ContextConfig) + +// WithIDs is a functional option for the Context. +func WithIDs(ids IDs) ContextOption { + return func(c *ContextConfig) { + c.IDs = ids + } +} + +type parseContext struct { + store []interface{} + ids IDs + refs map[string]Reference + blockOffset int + blockIndent int + delimiters *Delimiter + lastDelimiter *Delimiter + openedBlocks []Block +} + +// NewContext returns a new Context. +func NewContext(options ...ContextOption) Context { + cfg := &ContextConfig{ + IDs: newIDs(), + } + for _, option := range options { + option(cfg) + } + + return &parseContext{ + store: make([]interface{}, ContextKeyMax+1), + refs: map[string]Reference{}, + ids: cfg.IDs, + blockOffset: -1, + blockIndent: -1, + delimiters: nil, + lastDelimiter: nil, + openedBlocks: []Block{}, + } +} + +func (p *parseContext) Get(key ContextKey) interface{} { + return p.store[key] +} + +func (p *parseContext) ComputeIfAbsent(key ContextKey, f func() interface{}) interface{} { + v := p.store[key] + if v == nil { + v = f() + p.store[key] = v + } + return v +} + +func (p *parseContext) Set(key ContextKey, value interface{}) { + p.store[key] = value +} + +func (p *parseContext) IDs() IDs { + return p.ids +} + +func (p *parseContext) BlockOffset() int { + return p.blockOffset +} + +func (p *parseContext) SetBlockOffset(v int) { + p.blockOffset = v +} + +func (p *parseContext) BlockIndent() int { + return p.blockIndent +} + +func (p *parseContext) SetBlockIndent(v int) { + p.blockIndent = v +} + +func (p *parseContext) LastDelimiter() *Delimiter { + return p.lastDelimiter +} + +func (p *parseContext) FirstDelimiter() *Delimiter { + return p.delimiters +} + +func (p *parseContext) PushDelimiter(d *Delimiter) { + if p.delimiters == nil { + p.delimiters = d + p.lastDelimiter = d + } else { + l := p.lastDelimiter + p.lastDelimiter = d + l.NextDelimiter = d + d.PreviousDelimiter = l + } +} + +func (p *parseContext) RemoveDelimiter(d *Delimiter) { + if d.PreviousDelimiter == nil { + p.delimiters = d.NextDelimiter + } else { + d.PreviousDelimiter.NextDelimiter = d.NextDelimiter + if d.NextDelimiter != nil { + d.NextDelimiter.PreviousDelimiter = d.PreviousDelimiter + } + } + if d.NextDelimiter == nil { + p.lastDelimiter = d.PreviousDelimiter + } + if p.delimiters != nil { + p.delimiters.PreviousDelimiter = nil + } + if p.lastDelimiter != nil { + p.lastDelimiter.NextDelimiter = nil + } + d.NextDelimiter = nil + d.PreviousDelimiter = nil + if d.Length != 0 { + ast.MergeOrReplaceTextSegment(d.Parent(), d, d.Segment) + } else { + d.Parent().RemoveChild(d.Parent(), d) + } +} + +func (p *parseContext) ClearDelimiters(bottom ast.Node) { + if p.lastDelimiter == nil { + return + } + var c ast.Node + for c = p.lastDelimiter; c != nil && c != bottom; { + prev := c.PreviousSibling() + if d, ok := c.(*Delimiter); ok { + p.RemoveDelimiter(d) + } + c = prev + } +} + +func (p *parseContext) AddReference(ref Reference) { + key := util.ToLinkReference(ref.Label()) + if _, ok := p.refs[key]; !ok { + p.refs[key] = ref + } +} + +func (p *parseContext) Reference(label string) (Reference, bool) { + v, ok := p.refs[label] + return v, ok +} + +func (p *parseContext) References() []Reference { + ret := make([]Reference, 0, len(p.refs)) + for _, v := range p.refs { + ret = append(ret, v) + } + return ret +} + +func (p *parseContext) String() string { + refs := []string{} + for _, r := range p.refs { + refs = append(refs, r.String()) + } + + return fmt.Sprintf("Context{Store:%#v, Refs:%s}", p.store, strings.Join(refs, ",")) +} + +func (p *parseContext) OpenedBlocks() []Block { + return p.openedBlocks +} + +func (p *parseContext) SetOpenedBlocks(v []Block) { + p.openedBlocks = v +} + +func (p *parseContext) LastOpenedBlock() Block { + if l := len(p.openedBlocks); l != 0 { + return p.openedBlocks[l-1] + } + return Block{} +} + +func (p *parseContext) IsInLinkLabel() bool { + tlist := p.Get(linkLabelStateKey) + return tlist != nil +} + +// State represents parser's state. +// State is designed to use as a bit flag. +type State int + +const ( + none State = 1 << iota + + // Continue indicates parser can continue parsing. + Continue + + // Close indicates parser cannot parse anymore. + Close + + // HasChildren indicates parser may have child blocks. + HasChildren + + // NoChildren indicates parser does not have child blocks. + NoChildren + + // RequireParagraph indicates parser requires that the last node + // must be a paragraph and is not converted to other nodes by + // ParagraphTransformers. + RequireParagraph +) + +// A Config struct is a data structure that holds configuration of the Parser. +type Config struct { + Options map[OptionName]interface{} + BlockParsers util.PrioritizedSlice /**/ + InlineParsers util.PrioritizedSlice /**/ + ParagraphTransformers util.PrioritizedSlice /**/ + ASTTransformers util.PrioritizedSlice /**/ +} + +// NewConfig returns a new Config. +func NewConfig() *Config { + return &Config{ + Options: map[OptionName]interface{}{}, + BlockParsers: util.PrioritizedSlice{}, + InlineParsers: util.PrioritizedSlice{}, + ParagraphTransformers: util.PrioritizedSlice{}, + ASTTransformers: util.PrioritizedSlice{}, + } +} + +// An Option interface is a functional option type for the Parser. +type Option interface { + SetParserOption(*Config) +} + +// OptionName is a name of parser options. +type OptionName string + +// Attribute is an option name that spacify attributes of elements. +const optAttribute OptionName = "Attribute" + +type withAttribute struct { +} + +func (o *withAttribute) SetParserOption(c *Config) { + c.Options[optAttribute] = true +} + +// WithAttribute is a functional option that enables custom attributes. +func WithAttribute() Option { + return &withAttribute{} +} + +// A Parser interface parses Markdown text into AST nodes. +type Parser interface { + // Parse parses the given Markdown text into AST nodes. + Parse(reader text.Reader, opts ...ParseOption) ast.Node + + // AddOption adds the given option to this parser. + AddOptions(...Option) +} + +// A SetOptioner interface sets the given option to the object. +type SetOptioner interface { + // SetOption sets the given option to the object. + // Unacceptable options may be passed. + // Thus implementations must ignore unacceptable options. + SetOption(name OptionName, value interface{}) +} + +// A BlockParser interface parses a block level element like Paragraph, List, +// Blockquote etc. +type BlockParser interface { + // Trigger returns a list of characters that triggers Parse method of + // this parser. + // If Trigger returns a nil, Open will be called with any lines. + Trigger() []byte + + // Open parses the current line and returns a result of parsing. + // + // Open must not parse beyond the current line. + // If Open has been able to parse the current line, Open must advance a reader + // position by consumed byte length. + // + // If Open has not been able to parse the current line, Open should returns + // (nil, NoChildren). If Open has been able to parse the current line, Open + // should returns a new Block node and returns HasChildren or NoChildren. + Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) + + // Continue parses the current line and returns a result of parsing. + // + // Continue must not parse beyond the current line. + // If Continue has been able to parse the current line, Continue must advance + // a reader position by consumed byte length. + // + // If Continue has not been able to parse the current line, Continue should + // returns Close. If Continue has been able to parse the current line, + // Continue should returns (Continue | NoChildren) or + // (Continue | HasChildren) + Continue(node ast.Node, reader text.Reader, pc Context) State + + // Close will be called when the parser returns Close. + Close(node ast.Node, reader text.Reader, pc Context) + + // CanInterruptParagraph returns true if the parser can interrupt paragraphs, + // otherwise false. + CanInterruptParagraph() bool + + // CanAcceptIndentedLine returns true if the parser can open new node when + // the given line is being indented more than 3 spaces. + CanAcceptIndentedLine() bool +} + +// An InlineParser interface parses an inline level element like CodeSpan, Link etc. +type InlineParser interface { + // Trigger returns a list of characters that triggers Parse method of + // this parser. + // Trigger characters must be a punctuation or a halfspace. + // Halfspaces triggers this parser when character is any spaces characters or + // a head of line + Trigger() []byte + + // Parse parse the given block into an inline node. + // + // Parse can parse beyond the current line. + // If Parse has been able to parse the current line, it must advance a reader + // position by consumed byte length. + Parse(parent ast.Node, block text.Reader, pc Context) ast.Node +} + +// A CloseBlocker interface is a callback function that will be +// called when block is closed in the inline parsing. +type CloseBlocker interface { + // CloseBlock will be called when a block is closed. + CloseBlock(parent ast.Node, block text.Reader, pc Context) +} + +// A ParagraphTransformer transforms parsed Paragraph nodes. +// For example, link references are searched in parsed Paragraphs. +type ParagraphTransformer interface { + // Transform transforms the given paragraph. + Transform(node *ast.Paragraph, reader text.Reader, pc Context) +} + +// ASTTransformer transforms entire Markdown document AST tree. +type ASTTransformer interface { + // Transform transforms the given AST tree. + Transform(node *ast.Document, reader text.Reader, pc Context) +} + +// DefaultBlockParsers returns a new list of default BlockParsers. +// Priorities of default BlockParsers are: +// +// SetextHeadingParser, 100 +// ThematicBreakParser, 200 +// ListParser, 300 +// ListItemParser, 400 +// CodeBlockParser, 500 +// ATXHeadingParser, 600 +// FencedCodeBlockParser, 700 +// BlockquoteParser, 800 +// HTMLBlockParser, 900 +// ParagraphParser, 1000 +func DefaultBlockParsers() []util.PrioritizedValue { + return []util.PrioritizedValue{ + util.Prioritized(NewSetextHeadingParser(), 100), + util.Prioritized(NewThematicBreakParser(), 200), + util.Prioritized(NewListParser(), 300), + util.Prioritized(NewListItemParser(), 400), + util.Prioritized(NewCodeBlockParser(), 500), + util.Prioritized(NewATXHeadingParser(), 600), + util.Prioritized(NewFencedCodeBlockParser(), 700), + util.Prioritized(NewBlockquoteParser(), 800), + util.Prioritized(NewHTMLBlockParser(), 900), + util.Prioritized(NewParagraphParser(), 1000), + } +} + +// DefaultInlineParsers returns a new list of default InlineParsers. +// Priorities of default InlineParsers are: +// +// CodeSpanParser, 100 +// LinkParser, 200 +// AutoLinkParser, 300 +// RawHTMLParser, 400 +// EmphasisParser, 500 +func DefaultInlineParsers() []util.PrioritizedValue { + return []util.PrioritizedValue{ + util.Prioritized(NewCodeSpanParser(), 100), + util.Prioritized(NewLinkParser(), 200), + util.Prioritized(NewAutoLinkParser(), 300), + util.Prioritized(NewRawHTMLParser(), 400), + util.Prioritized(NewEmphasisParser(), 500), + } +} + +// DefaultParagraphTransformers returns a new list of default ParagraphTransformers. +// Priorities of default ParagraphTransformers are: +// +// LinkReferenceParagraphTransformer, 100 +func DefaultParagraphTransformers() []util.PrioritizedValue { + return []util.PrioritizedValue{ + util.Prioritized(LinkReferenceParagraphTransformer, 100), + } +} + +// A Block struct holds a node and correspond parser pair. +type Block struct { + // Node is a BlockNode. + Node ast.Node + // Parser is a BlockParser. + Parser BlockParser +} + +type parser struct { + options map[OptionName]interface{} + blockParsers [256][]BlockParser + freeBlockParsers []BlockParser + inlineParsers [256][]InlineParser + closeBlockers []CloseBlocker + paragraphTransformers []ParagraphTransformer + astTransformers []ASTTransformer + config *Config + initSync sync.Once +} + +type withBlockParsers struct { + value []util.PrioritizedValue +} + +func (o *withBlockParsers) SetParserOption(c *Config) { + c.BlockParsers = append(c.BlockParsers, o.value...) +} + +// WithBlockParsers is a functional option that allow you to add +// BlockParsers to the parser. +func WithBlockParsers(bs ...util.PrioritizedValue) Option { + return &withBlockParsers{bs} +} + +type withInlineParsers struct { + value []util.PrioritizedValue +} + +func (o *withInlineParsers) SetParserOption(c *Config) { + c.InlineParsers = append(c.InlineParsers, o.value...) +} + +// WithInlineParsers is a functional option that allow you to add +// InlineParsers to the parser. +func WithInlineParsers(bs ...util.PrioritizedValue) Option { + return &withInlineParsers{bs} +} + +type withParagraphTransformers struct { + value []util.PrioritizedValue +} + +func (o *withParagraphTransformers) SetParserOption(c *Config) { + c.ParagraphTransformers = append(c.ParagraphTransformers, o.value...) +} + +// WithParagraphTransformers is a functional option that allow you to add +// ParagraphTransformers to the parser. +func WithParagraphTransformers(ps ...util.PrioritizedValue) Option { + return &withParagraphTransformers{ps} +} + +type withASTTransformers struct { + value []util.PrioritizedValue +} + +func (o *withASTTransformers) SetParserOption(c *Config) { + c.ASTTransformers = append(c.ASTTransformers, o.value...) +} + +// WithASTTransformers is a functional option that allow you to add +// ASTTransformers to the parser. +func WithASTTransformers(ps ...util.PrioritizedValue) Option { + return &withASTTransformers{ps} +} + +type withOption struct { + name OptionName + value interface{} +} + +func (o *withOption) SetParserOption(c *Config) { + c.Options[o.name] = o.value +} + +// WithOption is a functional option that allow you to set +// an arbitrary option to the parser. +func WithOption(name OptionName, value interface{}) Option { + return &withOption{name, value} +} + +// NewParser returns a new Parser with given options. +func NewParser(options ...Option) Parser { + config := NewConfig() + for _, opt := range options { + opt.SetParserOption(config) + } + + p := &parser{ + options: map[OptionName]interface{}{}, + config: config, + } + + return p +} + +func (p *parser) AddOptions(opts ...Option) { + for _, opt := range opts { + opt.SetParserOption(p.config) + } +} + +func (p *parser) addBlockParser(v util.PrioritizedValue, options map[OptionName]interface{}) { + bp, ok := v.Value.(BlockParser) + if !ok { + panic(fmt.Sprintf("%v is not a BlockParser", v.Value)) + } + tcs := bp.Trigger() + so, ok := v.Value.(SetOptioner) + if ok { + for oname, ovalue := range options { + so.SetOption(oname, ovalue) + } + } + if tcs == nil { + p.freeBlockParsers = append(p.freeBlockParsers, bp) + } else { + for _, tc := range tcs { + if p.blockParsers[tc] == nil { + p.blockParsers[tc] = []BlockParser{} + } + p.blockParsers[tc] = append(p.blockParsers[tc], bp) + } + } +} + +func (p *parser) addInlineParser(v util.PrioritizedValue, options map[OptionName]interface{}) { + ip, ok := v.Value.(InlineParser) + if !ok { + panic(fmt.Sprintf("%v is not a InlineParser", v.Value)) + } + tcs := ip.Trigger() + so, ok := v.Value.(SetOptioner) + if ok { + for oname, ovalue := range options { + so.SetOption(oname, ovalue) + } + } + if cb, ok := ip.(CloseBlocker); ok { + p.closeBlockers = append(p.closeBlockers, cb) + } + for _, tc := range tcs { + if p.inlineParsers[tc] == nil { + p.inlineParsers[tc] = []InlineParser{} + } + p.inlineParsers[tc] = append(p.inlineParsers[tc], ip) + } +} + +func (p *parser) addParagraphTransformer(v util.PrioritizedValue, options map[OptionName]interface{}) { + pt, ok := v.Value.(ParagraphTransformer) + if !ok { + panic(fmt.Sprintf("%v is not a ParagraphTransformer", v.Value)) + } + so, ok := v.Value.(SetOptioner) + if ok { + for oname, ovalue := range options { + so.SetOption(oname, ovalue) + } + } + p.paragraphTransformers = append(p.paragraphTransformers, pt) +} + +func (p *parser) addASTTransformer(v util.PrioritizedValue, options map[OptionName]interface{}) { + at, ok := v.Value.(ASTTransformer) + if !ok { + panic(fmt.Sprintf("%v is not a ASTTransformer", v.Value)) + } + so, ok := v.Value.(SetOptioner) + if ok { + for oname, ovalue := range options { + so.SetOption(oname, ovalue) + } + } + p.astTransformers = append(p.astTransformers, at) +} + +// A ParseConfig struct is a data structure that holds configuration of the Parser.Parse. +type ParseConfig struct { + Context Context +} + +// A ParseOption is a functional option type for the Parser.Parse. +type ParseOption func(c *ParseConfig) + +// WithContext is a functional option that allow you to override +// a default context. +func WithContext(context Context) ParseOption { + return func(c *ParseConfig) { + c.Context = context + } +} + +func (p *parser) Parse(reader text.Reader, opts ...ParseOption) ast.Node { + p.initSync.Do(func() { + p.config.BlockParsers.Sort() + for _, v := range p.config.BlockParsers { + p.addBlockParser(v, p.config.Options) + } + for i := range p.blockParsers { + if p.blockParsers[i] != nil { + p.blockParsers[i] = append(p.blockParsers[i], p.freeBlockParsers...) + } + } + + p.config.InlineParsers.Sort() + for _, v := range p.config.InlineParsers { + p.addInlineParser(v, p.config.Options) + } + p.config.ParagraphTransformers.Sort() + for _, v := range p.config.ParagraphTransformers { + p.addParagraphTransformer(v, p.config.Options) + } + p.config.ASTTransformers.Sort() + for _, v := range p.config.ASTTransformers { + p.addASTTransformer(v, p.config.Options) + } + p.config = nil + }) + c := &ParseConfig{} + for _, opt := range opts { + opt(c) + } + if c.Context == nil { + c.Context = NewContext() + } + pc := c.Context + root := ast.NewDocument() + p.parseBlocks(root, reader, pc) + + blockReader := text.NewBlockReader(reader.Source(), nil) + p.walkBlock(root, func(node ast.Node) { + p.parseBlock(blockReader, node, pc) + }) + for _, at := range p.astTransformers { + at.Transform(root, reader, pc) + } + // root.Dump(reader.Source(), 0) + return root +} + +func (p *parser) transformParagraph(node *ast.Paragraph, reader text.Reader, pc Context) bool { + for _, pt := range p.paragraphTransformers { + pt.Transform(node, reader, pc) + if node.Parent() == nil { + return true + } + } + return false +} + +func (p *parser) closeBlocks(from, to int, reader text.Reader, pc Context) { + blocks := pc.OpenedBlocks() + for i := from; i >= to; i-- { + node := blocks[i].Node + blocks[i].Parser.Close(blocks[i].Node, reader, pc) + paragraph, ok := node.(*ast.Paragraph) + if ok && node.Parent() != nil { + p.transformParagraph(paragraph, reader, pc) + } + } + if from == len(blocks)-1 { + blocks = blocks[0:to] + } else { + blocks = append(blocks[0:to], blocks[from+1:]...) + } + pc.SetOpenedBlocks(blocks) +} + +type blockOpenResult int + +const ( + paragraphContinuation blockOpenResult = iota + 1 + newBlocksOpened + noBlocksOpened +) + +func (p *parser) openBlocks(parent ast.Node, blankLine bool, reader text.Reader, pc Context) blockOpenResult { + result := blockOpenResult(noBlocksOpened) + continuable := false + lastBlock := pc.LastOpenedBlock() + if lastBlock.Node != nil { + continuable = ast.IsParagraph(lastBlock.Node) + } +retry: + var bps []BlockParser + line, _ := reader.PeekLine() + w, pos := util.IndentWidth(line, reader.LineOffset()) + if w >= len(line) { + pc.SetBlockOffset(-1) + pc.SetBlockIndent(-1) + } else { + pc.SetBlockOffset(pos) + pc.SetBlockIndent(w) + } + if line == nil || line[0] == '\n' { + goto continuable + } + bps = p.freeBlockParsers + if pos < len(line) { + bps = p.blockParsers[line[pos]] + if bps == nil { + bps = p.freeBlockParsers + } + } + if bps == nil { + goto continuable + } + + for _, bp := range bps { + if continuable && result == noBlocksOpened && !bp.CanInterruptParagraph() { + continue + } + if w > 3 && !bp.CanAcceptIndentedLine() { + continue + } + lastBlock = pc.LastOpenedBlock() + last := lastBlock.Node + node, state := bp.Open(parent, reader, pc) + if node != nil { + // Parser requires last node to be a paragraph. + // With table extension: + // + // 0 + // -: + // - + // + // '-' on 3rd line seems a Setext heading because 1st and 2nd lines + // are being paragraph when the Settext heading parser tries to parse the 3rd + // line. + // But 1st line and 2nd line are a table. Thus this paragraph will be transformed + // by a paragraph transformer. So this text should be converted to a table and + // an empty list. + if state&RequireParagraph != 0 { + if last == parent.LastChild() { + // Opened paragraph may be transformed by ParagraphTransformers in + // closeBlocks(). + lastBlock.Parser.Close(last, reader, pc) + blocks := pc.OpenedBlocks() + pc.SetOpenedBlocks(blocks[0 : len(blocks)-1]) + if p.transformParagraph(last.(*ast.Paragraph), reader, pc) { + // Paragraph has been transformed. + // So this parser is considered as failing. + continuable = false + goto retry + } + } + } + node.SetBlankPreviousLines(blankLine) + if last != nil && last.Parent() == nil { + lastPos := len(pc.OpenedBlocks()) - 1 + p.closeBlocks(lastPos, lastPos, reader, pc) + } + parent.AppendChild(parent, node) + result = newBlocksOpened + be := Block{node, bp} + pc.SetOpenedBlocks(append(pc.OpenedBlocks(), be)) + if state&HasChildren != 0 { + parent = node + goto retry // try child block + } + break // no children, can not open more blocks on this line + } + } + +continuable: + if result == noBlocksOpened && continuable { + state := lastBlock.Parser.Continue(lastBlock.Node, reader, pc) + if state&Continue != 0 { + result = paragraphContinuation + } + } + return result +} + +type lineStat struct { + lineNum int + level int + isBlank bool +} + +func isBlankLine(lineNum, level int, stats []lineStat) bool { + ret := true + for i := len(stats) - 1 - level; i >= 0; i-- { + ret = false + s := stats[i] + if s.lineNum == lineNum { + if s.level < level && s.isBlank { + return true + } else if s.level == level { + return s.isBlank + } + } + if s.lineNum < lineNum { + return ret + } + } + return ret +} + +func (p *parser) parseBlocks(parent ast.Node, reader text.Reader, pc Context) { + pc.SetOpenedBlocks([]Block{}) + blankLines := make([]lineStat, 0, 128) + isBlank := false + for { // process blocks separated by blank lines + _, lines, ok := reader.SkipBlankLines() + if !ok { + return + } + lineNum, _ := reader.Position() + if lines != 0 { + blankLines = blankLines[0:0] + l := len(pc.OpenedBlocks()) + for i := 0; i < l; i++ { + blankLines = append(blankLines, lineStat{lineNum - 1, i, lines != 0}) + } + } + isBlank = isBlankLine(lineNum-1, 0, blankLines) + // first, we try to open blocks + if p.openBlocks(parent, isBlank, reader, pc) != newBlocksOpened { + return + } + reader.AdvanceLine() + for { // process opened blocks line by line + openedBlocks := pc.OpenedBlocks() + l := len(openedBlocks) + if l == 0 { + break + } + lastIndex := l - 1 + for i := 0; i < l; i++ { + be := openedBlocks[i] + line, _ := reader.PeekLine() + if line == nil { + p.closeBlocks(lastIndex, 0, reader, pc) + reader.AdvanceLine() + return + } + lineNum, _ := reader.Position() + blankLines = append(blankLines, lineStat{lineNum, i, util.IsBlank(line)}) + // If node is a paragraph, p.openBlocks determines whether it is continuable. + // So we do not process paragraphs here. + if !ast.IsParagraph(be.Node) { + state := be.Parser.Continue(be.Node, reader, pc) + if state&Continue != 0 { + // When current node is a container block and has no children, + // we try to open new child nodes + if state&HasChildren != 0 && i == lastIndex { + isBlank = isBlankLine(lineNum-1, i, blankLines) + p.openBlocks(be.Node, isBlank, reader, pc) + break + } + continue + } + } + // current node may be closed or lazy continuation + isBlank = isBlankLine(lineNum-1, i, blankLines) + thisParent := parent + if i != 0 { + thisParent = openedBlocks[i-1].Node + } + lastNode := openedBlocks[lastIndex].Node + result := p.openBlocks(thisParent, isBlank, reader, pc) + if result != paragraphContinuation { + // lastNode is a paragraph and was transformed by the paragraph + // transformers. + if openedBlocks[lastIndex].Node != lastNode { + lastIndex-- + } + p.closeBlocks(lastIndex, i, reader, pc) + } + break + } + + reader.AdvanceLine() + } + } +} + +func (p *parser) walkBlock(block ast.Node, cb func(node ast.Node)) { + for c := block.FirstChild(); c != nil; c = c.NextSibling() { + p.walkBlock(c, cb) + } + cb(block) +} + +func (p *parser) parseBlock(block text.BlockReader, parent ast.Node, pc Context) { + if parent.IsRaw() { + return + } + escaped := false + source := block.Source() + block.Reset(parent.Lines()) + for { + retry: + line, _ := block.PeekLine() + if line == nil { + break + } + lineLength := len(line) + softLinebreak := false + hardlineBreak := false + hasNewLine := line[lineLength-1] == '\n' + if lineLength >= 2 && line[lineLength-2] == '\\' && hasNewLine { // ends with \\n + lineLength -= 2 + hardlineBreak = true + + } else if lineLength >= 3 && line[lineLength-3] == '\\' && line[lineLength-2] == '\r' && hasNewLine { // ends with \\r\n + lineLength -= 3 + hardlineBreak = true + } else if lineLength >= 3 && line[lineLength-3] == ' ' && line[lineLength-2] == ' ' && hasNewLine { // ends with [space][space]\n + lineLength -= 3 + hardlineBreak = true + } else if lineLength >= 4 && line[lineLength-4] == ' ' && line[lineLength-3] == ' ' && line[lineLength-2] == '\r' && hasNewLine { // ends with [space][space]\r\n + lineLength -= 4 + hardlineBreak = true + } else if hasNewLine { + // If the line ends with a newline character, but it is not a hardlineBreak, then it is a softLinebreak + // If the line ends with a hardlineBreak, then it cannot end with a softLinebreak + // See https://spec.commonmark.org/0.29/#soft-line-breaks + softLinebreak = true + } + + l, startPosition := block.Position() + n := 0 + for i := 0; i < lineLength; i++ { + c := line[i] + if c == '\n' { + break + } + isSpace := util.IsSpace(c) + isPunct := util.IsPunct(c) + if (isPunct && !escaped) || isSpace || i == 0 { + parserChar := c + if isSpace || (i == 0 && !isPunct) { + parserChar = ' ' + } + ips := p.inlineParsers[parserChar] + if ips != nil { + block.Advance(n) + n = 0 + savedLine, savedPosition := block.Position() + if i != 0 { + _, currentPosition := block.Position() + ast.MergeOrAppendTextSegment(parent, startPosition.Between(currentPosition)) + _, startPosition = block.Position() + } + var inlineNode ast.Node + for _, ip := range ips { + inlineNode = ip.Parse(parent, block, pc) + if inlineNode != nil { + break + } + block.SetPosition(savedLine, savedPosition) + } + if inlineNode != nil { + parent.AppendChild(parent, inlineNode) + goto retry + } + } + } + if escaped { + escaped = false + n++ + continue + } + + if c == '\\' { + escaped = true + n++ + continue + } + + escaped = false + n++ + } + if n != 0 { + block.Advance(n) + } + currentL, currentPosition := block.Position() + if l != currentL { + continue + } + diff := startPosition.Between(currentPosition) + stop := diff.Stop + rest := diff.WithStop(stop) + text := ast.NewTextSegment(rest.TrimRightSpace(source)) + text.SetSoftLineBreak(softLinebreak) + text.SetHardLineBreak(hardlineBreak) + parent.AppendChild(parent, text) + block.AdvanceLine() + } + + ProcessDelimiters(nil, pc) + for _, ip := range p.closeBlockers { + ip.CloseBlock(parent, block, pc) + } +} diff --git a/vendor/github.com/yuin/goldmark/parser/raw_html.go b/vendor/github.com/yuin/goldmark/parser/raw_html.go new file mode 100644 index 0000000000..7fd696cc2c --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/raw_html.go @@ -0,0 +1,103 @@ +package parser + +import ( + "bytes" + "regexp" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type rawHTMLParser struct { +} + +var defaultRawHTMLParser = &rawHTMLParser{} + +// NewRawHTMLParser return a new InlineParser that can parse +// inline htmls +func NewRawHTMLParser() InlineParser { + return defaultRawHTMLParser +} + +func (s *rawHTMLParser) Trigger() []byte { + return []byte{'<'} +} + +func (s *rawHTMLParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node { + line, _ := block.PeekLine() + if len(line) > 1 && util.IsAlphaNumeric(line[1]) { + return s.parseMultiLineRegexp(openTagRegexp, block, pc) + } + if len(line) > 2 && line[1] == '/' && util.IsAlphaNumeric(line[2]) { + return s.parseMultiLineRegexp(closeTagRegexp, block, pc) + } + if bytes.HasPrefix(line, []byte("|`) +var processingInstructionRegexp = regexp.MustCompile(`^(?:<\?).*?(?:\?>)`) +var declRegexp = regexp.MustCompile(`^]*>`) +var cdataRegexp = regexp.MustCompile(``) + +func (s *rawHTMLParser) parseSingleLineRegexp(reg *regexp.Regexp, block text.Reader, pc Context) ast.Node { + line, segment := block.PeekLine() + match := reg.FindSubmatchIndex(line) + if match == nil { + return nil + } + node := ast.NewRawHTML() + node.Segments.Append(segment.WithStop(segment.Start + match[1])) + block.Advance(match[1]) + return node +} + +func (s *rawHTMLParser) parseMultiLineRegexp(reg *regexp.Regexp, block text.Reader, pc Context) ast.Node { + sline, ssegment := block.Position() + if block.Match(reg) { + node := ast.NewRawHTML() + eline, esegment := block.Position() + block.SetPosition(sline, ssegment) + for { + line, segment := block.PeekLine() + if line == nil { + break + } + l, _ := block.Position() + start := segment.Start + if l == sline { + start = ssegment.Start + } + end := segment.Stop + if l == eline { + end = esegment.Start + } + + node.Segments.Append(text.NewSegment(start, end)) + if l == eline { + block.Advance(end - start) + break + } else { + block.AdvanceLine() + } + } + return node + } + return nil +} diff --git a/vendor/github.com/yuin/goldmark/parser/setext_headings.go b/vendor/github.com/yuin/goldmark/parser/setext_headings.go new file mode 100644 index 0000000000..686efe179c --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/setext_headings.go @@ -0,0 +1,126 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +var temporaryParagraphKey = NewContextKey() + +type setextHeadingParser struct { + HeadingConfig +} + +func matchesSetextHeadingBar(line []byte) (byte, bool) { + start := 0 + end := len(line) + space := util.TrimLeftLength(line, []byte{' '}) + if space > 3 { + return 0, false + } + start += space + level1 := util.TrimLeftLength(line[start:end], []byte{'='}) + c := byte('=') + var level2 int + if level1 == 0 { + level2 = util.TrimLeftLength(line[start:end], []byte{'-'}) + c = '-' + } + if util.IsSpace(line[end-1]) { + end -= util.TrimRightSpaceLength(line[start:end]) + } + if !((level1 > 0 && start+level1 == end) || (level2 > 0 && start+level2 == end)) { + return 0, false + } + return c, true +} + +// NewSetextHeadingParser return a new BlockParser that can parse Setext headings. +func NewSetextHeadingParser(opts ...HeadingOption) BlockParser { + p := &setextHeadingParser{} + for _, o := range opts { + o.SetHeadingOption(&p.HeadingConfig) + } + return p +} + +func (b *setextHeadingParser) Trigger() []byte { + return []byte{'-', '='} +} + +func (b *setextHeadingParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + last := pc.LastOpenedBlock().Node + if last == nil { + return nil, NoChildren + } + paragraph, ok := last.(*ast.Paragraph) + if !ok || paragraph.Parent() != parent { + return nil, NoChildren + } + line, segment := reader.PeekLine() + c, ok := matchesSetextHeadingBar(line) + if !ok { + return nil, NoChildren + } + level := 1 + if c == '-' { + level = 2 + } + node := ast.NewHeading(level) + node.Lines().Append(segment) + pc.Set(temporaryParagraphKey, last) + return node, NoChildren | RequireParagraph +} + +func (b *setextHeadingParser) Continue(node ast.Node, reader text.Reader, pc Context) State { + return Close +} + +func (b *setextHeadingParser) Close(node ast.Node, reader text.Reader, pc Context) { + heading := node.(*ast.Heading) + segment := node.Lines().At(0) + heading.Lines().Clear() + tmp := pc.Get(temporaryParagraphKey).(*ast.Paragraph) + pc.Set(temporaryParagraphKey, nil) + if tmp.Lines().Len() == 0 { + next := heading.NextSibling() + segment = segment.TrimLeftSpace(reader.Source()) + if next == nil || !ast.IsParagraph(next) { + para := ast.NewParagraph() + para.Lines().Append(segment) + heading.Parent().InsertAfter(heading.Parent(), heading, para) + } else { + next.(ast.Node).Lines().Unshift(segment) + } + heading.Parent().RemoveChild(heading.Parent(), heading) + } else { + heading.SetLines(tmp.Lines()) + heading.SetBlankPreviousLines(tmp.HasBlankPreviousLines()) + tp := tmp.Parent() + if tp != nil { + tp.RemoveChild(tp, tmp) + } + } + + if b.Attribute { + parseLastLineAttributes(node, reader, pc) + } + + if b.AutoHeadingID { + id, ok := node.AttributeString("id") + if !ok { + generateAutoHeadingID(heading, reader, pc) + } else { + pc.IDs().Put(id.([]byte)) + } + } +} + +func (b *setextHeadingParser) CanInterruptParagraph() bool { + return true +} + +func (b *setextHeadingParser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/parser/thematic_break.go b/vendor/github.com/yuin/goldmark/parser/thematic_break.go new file mode 100644 index 0000000000..db20a1e7aa --- /dev/null +++ b/vendor/github.com/yuin/goldmark/parser/thematic_break.go @@ -0,0 +1,75 @@ +package parser + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type thematicBreakPraser struct { +} + +var defaultThematicBreakPraser = &thematicBreakPraser{} + +// NewThematicBreakParser returns a new BlockParser that +// parses thematic breaks. +func NewThematicBreakParser() BlockParser { + return defaultThematicBreakPraser +} + +func isThematicBreak(line []byte, offset int) bool { + w, pos := util.IndentWidth(line, offset) + if w > 3 { + return false + } + mark := byte(0) + count := 0 + for i := pos; i < len(line); i++ { + c := line[i] + if util.IsSpace(c) { + continue + } + if mark == 0 { + mark = c + count = 1 + if mark == '*' || mark == '-' || mark == '_' { + continue + } + return false + } + if c != mark { + return false + } + count++ + } + return count > 2 +} + +func (b *thematicBreakPraser) Trigger() []byte { + return []byte{'-', '*', '_'} +} + +func (b *thematicBreakPraser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) { + line, segment := reader.PeekLine() + if isThematicBreak(line, reader.LineOffset()) { + reader.Advance(segment.Len() - 1) + return ast.NewThematicBreak(), NoChildren + } + return nil, NoChildren +} + +func (b *thematicBreakPraser) Continue(node ast.Node, reader text.Reader, pc Context) State { + return Close +} + +func (b *thematicBreakPraser) Close(node ast.Node, reader text.Reader, pc Context) { + // nothing to do +} + +func (b *thematicBreakPraser) CanInterruptParagraph() bool { + return true +} + +func (b *thematicBreakPraser) CanAcceptIndentedLine() bool { + return false +} diff --git a/vendor/github.com/yuin/goldmark/renderer/html/html.go b/vendor/github.com/yuin/goldmark/renderer/html/html.go new file mode 100644 index 0000000000..d8ff7e55ad --- /dev/null +++ b/vendor/github.com/yuin/goldmark/renderer/html/html.go @@ -0,0 +1,805 @@ +package html + +import ( + "bytes" + "fmt" + "strconv" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/util" +) + +// A Config struct has configurations for the HTML based renderers. +type Config struct { + Writer Writer + HardWraps bool + XHTML bool + Unsafe bool +} + +// NewConfig returns a new Config with defaults. +func NewConfig() Config { + return Config{ + Writer: DefaultWriter, + HardWraps: false, + XHTML: false, + Unsafe: false, + } +} + +// SetOption implements renderer.NodeRenderer.SetOption. +func (c *Config) SetOption(name renderer.OptionName, value interface{}) { + switch name { + case optHardWraps: + c.HardWraps = value.(bool) + case optXHTML: + c.XHTML = value.(bool) + case optUnsafe: + c.Unsafe = value.(bool) + case optTextWriter: + c.Writer = value.(Writer) + } +} + +// An Option interface sets options for HTML based renderers. +type Option interface { + SetHTMLOption(*Config) +} + +// TextWriter is an option name used in WithWriter. +const optTextWriter renderer.OptionName = "Writer" + +type withWriter struct { + value Writer +} + +func (o *withWriter) SetConfig(c *renderer.Config) { + c.Options[optTextWriter] = o.value +} + +func (o *withWriter) SetHTMLOption(c *Config) { + c.Writer = o.value +} + +// WithWriter is a functional option that allow you to set the given writer to +// the renderer. +func WithWriter(writer Writer) interface { + renderer.Option + Option +} { + return &withWriter{writer} +} + +// HardWraps is an option name used in WithHardWraps. +const optHardWraps renderer.OptionName = "HardWraps" + +type withHardWraps struct { +} + +func (o *withHardWraps) SetConfig(c *renderer.Config) { + c.Options[optHardWraps] = true +} + +func (o *withHardWraps) SetHTMLOption(c *Config) { + c.HardWraps = true +} + +// WithHardWraps is a functional option that indicates whether softline breaks +// should be rendered as '
    '. +func WithHardWraps() interface { + renderer.Option + Option +} { + return &withHardWraps{} +} + +// XHTML is an option name used in WithXHTML. +const optXHTML renderer.OptionName = "XHTML" + +type withXHTML struct { +} + +func (o *withXHTML) SetConfig(c *renderer.Config) { + c.Options[optXHTML] = true +} + +func (o *withXHTML) SetHTMLOption(c *Config) { + c.XHTML = true +} + +// WithXHTML is a functional option indicates that nodes should be rendered in +// xhtml instead of HTML5. +func WithXHTML() interface { + Option + renderer.Option +} { + return &withXHTML{} +} + +// Unsafe is an option name used in WithUnsafe. +const optUnsafe renderer.OptionName = "Unsafe" + +type withUnsafe struct { +} + +func (o *withUnsafe) SetConfig(c *renderer.Config) { + c.Options[optUnsafe] = true +} + +func (o *withUnsafe) SetHTMLOption(c *Config) { + c.Unsafe = true +} + +// WithUnsafe is a functional option that renders dangerous contents +// (raw htmls and potentially dangerous links) as it is. +func WithUnsafe() interface { + renderer.Option + Option +} { + return &withUnsafe{} +} + +// A Renderer struct is an implementation of renderer.NodeRenderer that renders +// nodes as (X)HTML. +type Renderer struct { + Config +} + +// NewRenderer returns a new Renderer with given options. +func NewRenderer(opts ...Option) renderer.NodeRenderer { + r := &Renderer{ + Config: NewConfig(), + } + + for _, opt := range opts { + opt.SetHTMLOption(&r.Config) + } + return r +} + +// RegisterFuncs implements NodeRenderer.RegisterFuncs . +func (r *Renderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + // blocks + + reg.Register(ast.KindDocument, r.renderDocument) + reg.Register(ast.KindHeading, r.renderHeading) + reg.Register(ast.KindBlockquote, r.renderBlockquote) + reg.Register(ast.KindCodeBlock, r.renderCodeBlock) + reg.Register(ast.KindFencedCodeBlock, r.renderFencedCodeBlock) + reg.Register(ast.KindHTMLBlock, r.renderHTMLBlock) + reg.Register(ast.KindList, r.renderList) + reg.Register(ast.KindListItem, r.renderListItem) + reg.Register(ast.KindParagraph, r.renderParagraph) + reg.Register(ast.KindTextBlock, r.renderTextBlock) + reg.Register(ast.KindThematicBreak, r.renderThematicBreak) + + // inlines + + reg.Register(ast.KindAutoLink, r.renderAutoLink) + reg.Register(ast.KindCodeSpan, r.renderCodeSpan) + reg.Register(ast.KindEmphasis, r.renderEmphasis) + reg.Register(ast.KindImage, r.renderImage) + reg.Register(ast.KindLink, r.renderLink) + reg.Register(ast.KindRawHTML, r.renderRawHTML) + reg.Register(ast.KindText, r.renderText) + reg.Register(ast.KindString, r.renderString) +} + +func (r *Renderer) writeLines(w util.BufWriter, source []byte, n ast.Node) { + l := n.Lines().Len() + for i := 0; i < l; i++ { + line := n.Lines().At(i) + r.Writer.RawWrite(w, line.Value(source)) + } +} + +// GlobalAttributeFilter defines attribute names which any elements can have. +var GlobalAttributeFilter = util.NewBytesFilter( + []byte("accesskey"), + []byte("autocapitalize"), + []byte("class"), + []byte("contenteditable"), + []byte("contextmenu"), + []byte("dir"), + []byte("draggable"), + []byte("dropzone"), + []byte("hidden"), + []byte("id"), + []byte("itemprop"), + []byte("lang"), + []byte("slot"), + []byte("spellcheck"), + []byte("style"), + []byte("tabindex"), + []byte("title"), + []byte("translate"), +) + +func (r *Renderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + // nothing to do + return ast.WalkContinue, nil +} + +// HeadingAttributeFilter defines attribute names which heading elements can have +var HeadingAttributeFilter = GlobalAttributeFilter + +func (r *Renderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.Heading) + if entering { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("\n") + } + return ast.WalkContinue, nil +} + +// BlockquoteAttributeFilter defines attribute names which blockquote elements can have +var BlockquoteAttributeFilter = GlobalAttributeFilter.Extend( + []byte("cite"), +) + +func (r *Renderer) renderBlockquote(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("
    \n") + } + } else { + _, _ = w.WriteString("
    \n") + } + return ast.WalkContinue, nil +} + +func (r *Renderer) renderCodeBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + _, _ = w.WriteString("
    ")
    +		r.writeLines(w, source, n)
    +	} else {
    +		_, _ = w.WriteString("
    \n") + } + return ast.WalkContinue, nil +} + +func (r *Renderer) renderFencedCodeBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.FencedCodeBlock) + if entering { + _, _ = w.WriteString("
    ')
    +		r.writeLines(w, source, n)
    +	} else {
    +		_, _ = w.WriteString("
    \n") + } + return ast.WalkContinue, nil +} + +func (r *Renderer) renderHTMLBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.HTMLBlock) + if entering { + if r.Unsafe { + l := n.Lines().Len() + for i := 0; i < l; i++ { + line := n.Lines().At(i) + _, _ = w.Write(line.Value(source)) + } + } else { + _, _ = w.WriteString("\n") + } + } else { + if n.HasClosure() { + if r.Unsafe { + closure := n.ClosureLine + _, _ = w.Write(closure.Value(source)) + } else { + _, _ = w.WriteString("\n") + } + } + } + return ast.WalkContinue, nil +} + +// ListAttributeFilter defines attribute names which list elements can have. +var ListAttributeFilter = GlobalAttributeFilter.Extend( + []byte("start"), + []byte("reversed"), + []byte("type"), +) + +func (r *Renderer) renderList(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.List) + tag := "ul" + if n.IsOrdered() { + tag = "ol" + } + if entering { + _ = w.WriteByte('<') + _, _ = w.WriteString(tag) + if n.IsOrdered() && n.Start != 1 { + fmt.Fprintf(w, " start=\"%d\"", n.Start) + } + if n.Attributes() != nil { + RenderAttributes(w, n, ListAttributeFilter) + } + _, _ = w.WriteString(">\n") + } else { + _, _ = w.WriteString("\n") + } + return ast.WalkContinue, nil +} + +// ListItemAttributeFilter defines attribute names which list item elements can have. +var ListItemAttributeFilter = GlobalAttributeFilter.Extend( + []byte("value"), +) + +func (r *Renderer) renderListItem(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("
  • ") + } + fc := n.FirstChild() + if fc != nil { + if _, ok := fc.(*ast.TextBlock); !ok { + _ = w.WriteByte('\n') + } + } + } else { + _, _ = w.WriteString("
  • \n") + } + return ast.WalkContinue, nil +} + +// ParagraphAttributeFilter defines attribute names which paragraph elements can have. +var ParagraphAttributeFilter = GlobalAttributeFilter + +func (r *Renderer) renderParagraph(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("

    ") + } + } else { + _, _ = w.WriteString("

    \n") + } + return ast.WalkContinue, nil +} + +func (r *Renderer) renderTextBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + if _, ok := n.NextSibling().(ast.Node); ok && n.FirstChild() != nil { + _ = w.WriteByte('\n') + } + } + return ast.WalkContinue, nil +} + +// ThematicAttributeFilter defines attribute names which hr elements can have. +var ThematicAttributeFilter = GlobalAttributeFilter.Extend( + []byte("align"), // [Deprecated] + []byte("color"), // [Not Standardized] + []byte("noshade"), // [Deprecated] + []byte("size"), // [Deprecated] + []byte("width"), // [Deprecated] +) + +func (r *Renderer) renderThematicBreak(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + _, _ = w.WriteString("\n") + } else { + _, _ = w.WriteString(">\n") + } + return ast.WalkContinue, nil +} + +// LinkAttributeFilter defines attribute names which link elements can have. +var LinkAttributeFilter = GlobalAttributeFilter.Extend( + []byte("download"), + // []byte("href"), + []byte("hreflang"), + []byte("media"), + []byte("ping"), + []byte("referrerpolicy"), + []byte("rel"), + []byte("shape"), + []byte("target"), +) + +func (r *Renderer) renderAutoLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.AutoLink) + if !entering { + return ast.WalkContinue, nil + } + _, _ = w.WriteString(`') + } else { + _, _ = w.WriteString(`">`) + } + _, _ = w.Write(util.EscapeHTML(label)) + _, _ = w.WriteString(``) + return ast.WalkContinue, nil +} + +// CodeAttributeFilter defines attribute names which code elements can have. +var CodeAttributeFilter = GlobalAttributeFilter + +func (r *Renderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("") + } + for c := n.FirstChild(); c != nil; c = c.NextSibling() { + segment := c.(*ast.Text).Segment + value := segment.Value(source) + if bytes.HasSuffix(value, []byte("\n")) { + r.Writer.RawWrite(w, value[:len(value)-1]) + if c != n.LastChild() { + r.Writer.RawWrite(w, []byte(" ")) + } + } else { + r.Writer.RawWrite(w, value) + } + } + return ast.WalkSkipChildren, nil + } + _, _ = w.WriteString("") + return ast.WalkContinue, nil +} + +// EmphasisAttributeFilter defines attribute names which emphasis elements can have. +var EmphasisAttributeFilter = GlobalAttributeFilter + +func (r *Renderer) renderEmphasis(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.Emphasis) + tag := "em" + if n.Level == 2 { + tag = "strong" + } + if entering { + _ = w.WriteByte('<') + _, _ = w.WriteString(tag) + if n.Attributes() != nil { + RenderAttributes(w, n, EmphasisAttributeFilter) + } + _ = w.WriteByte('>') + } else { + _, _ = w.WriteString("') + } + return ast.WalkContinue, nil +} + +func (r *Renderer) renderLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.Link) + if entering { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("") + } + return ast.WalkContinue, nil +} + +// ImageAttributeFilter defines attribute names which image elements can have. +var ImageAttributeFilter = GlobalAttributeFilter.Extend( + []byte("align"), + []byte("border"), + []byte("crossorigin"), + []byte("decoding"), + []byte("height"), + []byte("importance"), + []byte("intrinsicsize"), + []byte("ismap"), + []byte("loading"), + []byte("referrerpolicy"), + []byte("sizes"), + []byte("srcset"), + []byte("usemap"), + []byte("width"), +) + +func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + n := node.(*ast.Image) + _, _ = w.WriteString("`)
+	_, _ = w.Write(util.EscapeHTML(n.Text(source)))
+	_ = w.WriteByte('") + } else { + _, _ = w.WriteString(">") + } + return ast.WalkSkipChildren, nil +} + +func (r *Renderer) renderRawHTML(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkSkipChildren, nil + } + if r.Unsafe { + n := node.(*ast.RawHTML) + l := n.Segments.Len() + for i := 0; i < l; i++ { + segment := n.Segments.At(i) + _, _ = w.Write(segment.Value(source)) + } + return ast.WalkSkipChildren, nil + } + _, _ = w.WriteString("") + return ast.WalkSkipChildren, nil +} + +func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + n := node.(*ast.Text) + segment := n.Segment + if n.IsRaw() { + r.Writer.RawWrite(w, segment.Value(source)) + } else { + r.Writer.Write(w, segment.Value(source)) + if n.HardLineBreak() || (n.SoftLineBreak() && r.HardWraps) { + if r.XHTML { + _, _ = w.WriteString("
    \n") + } else { + _, _ = w.WriteString("
    \n") + } + } else if n.SoftLineBreak() { + _ = w.WriteByte('\n') + } + } + return ast.WalkContinue, nil +} + +func (r *Renderer) renderString(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + if !entering { + return ast.WalkContinue, nil + } + n := node.(*ast.String) + if n.IsCode() { + _, _ = w.Write(n.Value) + } else { + if n.IsRaw() { + r.Writer.RawWrite(w, n.Value) + } else { + r.Writer.Write(w, n.Value) + } + } + return ast.WalkContinue, nil +} + +var dataPrefix = []byte("data-") + +// RenderAttributes renders given node's attributes. +// You can specify attribute names to render by the filter. +// If filter is nil, RenderAttributes renders all attributes. +func RenderAttributes(w util.BufWriter, node ast.Node, filter util.BytesFilter) { + for _, attr := range node.Attributes() { + if filter != nil && !filter.Contains(attr.Name) { + if !bytes.HasPrefix(attr.Name, dataPrefix) { + continue + } + } + _, _ = w.WriteString(" ") + _, _ = w.Write(attr.Name) + _, _ = w.WriteString(`="`) + // TODO: convert numeric values to strings + _, _ = w.Write(util.EscapeHTML(attr.Value.([]byte))) + _ = w.WriteByte('"') + } +} + +// A Writer interface writes textual contents to a writer. +type Writer interface { + // Write writes the given source to writer with resolving references and unescaping + // backslash escaped characters. + Write(writer util.BufWriter, source []byte) + + // RawWrite writes the given source to writer without resolving references and + // unescaping backslash escaped characters. + RawWrite(writer util.BufWriter, source []byte) +} + +type defaultWriter struct { +} + +func escapeRune(writer util.BufWriter, r rune) { + if r < 256 { + v := util.EscapeHTMLByte(byte(r)) + if v != nil { + _, _ = writer.Write(v) + return + } + } + _, _ = writer.WriteRune(util.ToValidRune(r)) +} + +func (d *defaultWriter) RawWrite(writer util.BufWriter, source []byte) { + n := 0 + l := len(source) + for i := 0; i < l; i++ { + v := util.EscapeHTMLByte(source[i]) + if v != nil { + _, _ = writer.Write(source[i-n : i]) + n = 0 + _, _ = writer.Write(v) + continue + } + n++ + } + if n != 0 { + _, _ = writer.Write(source[l-n:]) + } +} + +func (d *defaultWriter) Write(writer util.BufWriter, source []byte) { + escaped := false + var ok bool + limit := len(source) + n := 0 + for i := 0; i < limit; i++ { + c := source[i] + if escaped { + if util.IsPunct(c) { + d.RawWrite(writer, source[n:i-1]) + n = i + escaped = false + continue + } + } + if c == '&' { + pos := i + next := i + 1 + if next < limit && source[next] == '#' { + nnext := next + 1 + if nnext < limit { + nc := source[nnext] + // code point like #x22; + if nnext < limit && nc == 'x' || nc == 'X' { + start := nnext + 1 + i, ok = util.ReadWhile(source, [2]int{start, limit}, util.IsHexDecimal) + if ok && i < limit && source[i] == ';' { + v, _ := strconv.ParseUint(util.BytesToReadOnlyString(source[start:i]), 16, 32) + d.RawWrite(writer, source[n:pos]) + n = i + 1 + escapeRune(writer, rune(v)) + continue + } + // code point like #1234; + } else if nc >= '0' && nc <= '9' { + start := nnext + i, ok = util.ReadWhile(source, [2]int{start, limit}, util.IsNumeric) + if ok && i < limit && i-start < 8 && source[i] == ';' { + v, _ := strconv.ParseUint(util.BytesToReadOnlyString(source[start:i]), 0, 32) + d.RawWrite(writer, source[n:pos]) + n = i + 1 + escapeRune(writer, rune(v)) + continue + } + } + } + } else { + start := next + i, ok = util.ReadWhile(source, [2]int{start, limit}, util.IsAlphaNumeric) + // entity reference + if ok && i < limit && source[i] == ';' { + name := util.BytesToReadOnlyString(source[start:i]) + entity, ok := util.LookUpHTML5EntityByName(name) + if ok { + d.RawWrite(writer, source[n:pos]) + n = i + 1 + d.RawWrite(writer, entity.Characters) + continue + } + } + } + i = next - 1 + } + if c == '\\' { + escaped = true + continue + } + escaped = false + } + d.RawWrite(writer, source[n:]) +} + +// DefaultWriter is a default implementation of the Writer. +var DefaultWriter = &defaultWriter{} + +var bDataImage = []byte("data:image/") +var bPng = []byte("png;") +var bGif = []byte("gif;") +var bJpeg = []byte("jpeg;") +var bWebp = []byte("webp;") +var bJs = []byte("javascript:") +var bVb = []byte("vbscript:") +var bFile = []byte("file:") +var bData = []byte("data:") + +// IsDangerousURL returns true if the given url seems a potentially dangerous url, +// otherwise false. +func IsDangerousURL(url []byte) bool { + if bytes.HasPrefix(url, bDataImage) && len(url) >= 11 { + v := url[11:] + if bytes.HasPrefix(v, bPng) || bytes.HasPrefix(v, bGif) || + bytes.HasPrefix(v, bJpeg) || bytes.HasPrefix(v, bWebp) { + return false + } + return true + } + return bytes.HasPrefix(url, bJs) || bytes.HasPrefix(url, bVb) || + bytes.HasPrefix(url, bFile) || bytes.HasPrefix(url, bData) +} diff --git a/vendor/github.com/yuin/goldmark/renderer/renderer.go b/vendor/github.com/yuin/goldmark/renderer/renderer.go new file mode 100644 index 0000000000..10f6d40104 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/renderer/renderer.go @@ -0,0 +1,174 @@ +// Package renderer renders the given AST to certain formats. +package renderer + +import ( + "bufio" + "io" + "sync" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/util" +) + +// A Config struct is a data structure that holds configuration of the Renderer. +type Config struct { + Options map[OptionName]interface{} + NodeRenderers util.PrioritizedSlice +} + +// NewConfig returns a new Config +func NewConfig() *Config { + return &Config{ + Options: map[OptionName]interface{}{}, + NodeRenderers: util.PrioritizedSlice{}, + } +} + +// An OptionName is a name of the option. +type OptionName string + +// An Option interface is a functional option type for the Renderer. +type Option interface { + SetConfig(*Config) +} + +type withNodeRenderers struct { + value []util.PrioritizedValue +} + +func (o *withNodeRenderers) SetConfig(c *Config) { + c.NodeRenderers = append(c.NodeRenderers, o.value...) +} + +// WithNodeRenderers is a functional option that allow you to add +// NodeRenderers to the renderer. +func WithNodeRenderers(ps ...util.PrioritizedValue) Option { + return &withNodeRenderers{ps} +} + +type withOption struct { + name OptionName + value interface{} +} + +func (o *withOption) SetConfig(c *Config) { + c.Options[o.name] = o.value +} + +// WithOption is a functional option that allow you to set +// an arbitrary option to the parser. +func WithOption(name OptionName, value interface{}) Option { + return &withOption{name, value} +} + +// A SetOptioner interface sets given option to the object. +type SetOptioner interface { + // SetOption sets given option to the object. + // Unacceptable options may be passed. + // Thus implementations must ignore unacceptable options. + SetOption(name OptionName, value interface{}) +} + +// NodeRendererFunc is a function that renders a given node. +type NodeRendererFunc func(writer util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) + +// A NodeRenderer interface offers NodeRendererFuncs. +type NodeRenderer interface { + // RendererFuncs registers NodeRendererFuncs to given NodeRendererFuncRegisterer. + RegisterFuncs(NodeRendererFuncRegisterer) +} + +// A NodeRendererFuncRegisterer registers +type NodeRendererFuncRegisterer interface { + // Register registers given NodeRendererFunc to this object. + Register(ast.NodeKind, NodeRendererFunc) +} + +// A Renderer interface renders given AST node to given +// writer with given Renderer. +type Renderer interface { + Render(w io.Writer, source []byte, n ast.Node) error + + // AddOptions adds given option to this renderer. + AddOptions(...Option) +} + +type renderer struct { + config *Config + options map[OptionName]interface{} + nodeRendererFuncsTmp map[ast.NodeKind]NodeRendererFunc + maxKind int + nodeRendererFuncs []NodeRendererFunc + initSync sync.Once +} + +// NewRenderer returns a new Renderer with given options. +func NewRenderer(options ...Option) Renderer { + config := NewConfig() + for _, opt := range options { + opt.SetConfig(config) + } + + r := &renderer{ + options: map[OptionName]interface{}{}, + config: config, + nodeRendererFuncsTmp: map[ast.NodeKind]NodeRendererFunc{}, + } + + return r +} + +func (r *renderer) AddOptions(opts ...Option) { + for _, opt := range opts { + opt.SetConfig(r.config) + } +} + +func (r *renderer) Register(kind ast.NodeKind, v NodeRendererFunc) { + r.nodeRendererFuncsTmp[kind] = v + if int(kind) > r.maxKind { + r.maxKind = int(kind) + } +} + +// Render renders the given AST node to the given writer with the given Renderer. +func (r *renderer) Render(w io.Writer, source []byte, n ast.Node) error { + r.initSync.Do(func() { + r.options = r.config.Options + r.config.NodeRenderers.Sort() + l := len(r.config.NodeRenderers) + for i := l - 1; i >= 0; i-- { + v := r.config.NodeRenderers[i] + nr, _ := v.Value.(NodeRenderer) + if se, ok := v.Value.(SetOptioner); ok { + for oname, ovalue := range r.options { + se.SetOption(oname, ovalue) + } + } + nr.RegisterFuncs(r) + } + r.nodeRendererFuncs = make([]NodeRendererFunc, r.maxKind+1) + for kind, nr := range r.nodeRendererFuncsTmp { + r.nodeRendererFuncs[kind] = nr + } + r.config = nil + r.nodeRendererFuncsTmp = nil + }) + writer, ok := w.(util.BufWriter) + if !ok { + writer = bufio.NewWriter(w) + } + err := ast.Walk(n, func(n ast.Node, entering bool) (ast.WalkStatus, error) { + s := ast.WalkStatus(ast.WalkContinue) + var err error + f := r.nodeRendererFuncs[n.Kind()] + if f != nil { + s, err = f(writer, source, n, entering) + } + return s, err + }) + if err != nil { + return err + } + return writer.Flush() +} diff --git a/vendor/github.com/yuin/goldmark/text/reader.go b/vendor/github.com/yuin/goldmark/text/reader.go new file mode 100644 index 0000000000..df25e5457c --- /dev/null +++ b/vendor/github.com/yuin/goldmark/text/reader.go @@ -0,0 +1,543 @@ +package text + +import ( + "io" + "regexp" + "unicode/utf8" + + "github.com/yuin/goldmark/util" +) + +const invalidValue = -1 + +// EOF indicates the end of file. +const EOF = byte(0xff) + +// A Reader interface provides abstracted method for reading text. +type Reader interface { + io.RuneReader + + // Source returns a source of the reader. + Source() []byte + + // ResetPosition resets positions. + ResetPosition() + + // Peek returns a byte at current position without advancing the internal pointer. + Peek() byte + + // PeekLine returns the current line without advancing the internal pointer. + PeekLine() ([]byte, Segment) + + // PrecendingCharacter returns a character just before current internal pointer. + PrecendingCharacter() rune + + // Value returns a value of the given segment. + Value(Segment) []byte + + // LineOffset returns a distance from the line head to current position. + LineOffset() int + + // Position returns current line number and position. + Position() (int, Segment) + + // SetPosition sets current line number and position. + SetPosition(int, Segment) + + // SetPadding sets padding to the reader. + SetPadding(int) + + // Advance advances the internal pointer. + Advance(int) + + // AdvanceAndSetPadding advances the internal pointer and add padding to the + // reader. + AdvanceAndSetPadding(int, int) + + // AdvanceLine advances the internal pointer to the next line head. + AdvanceLine() + + // SkipSpaces skips space characters and returns a non-blank line. + // If it reaches EOF, returns false. + SkipSpaces() (Segment, int, bool) + + // SkipSpaces skips blank lines and returns a non-blank line. + // If it reaches EOF, returns false. + SkipBlankLines() (Segment, int, bool) + + // Match performs regular expression matching to current line. + Match(reg *regexp.Regexp) bool + + // Match performs regular expression searching to current line. + FindSubMatch(reg *regexp.Regexp) [][]byte +} + +type reader struct { + source []byte + sourceLength int + line int + peekedLine []byte + pos Segment + head int + lineOffset int +} + +// NewReader return a new Reader that can read UTF-8 bytes . +func NewReader(source []byte) Reader { + r := &reader{ + source: source, + sourceLength: len(source), + } + r.ResetPosition() + return r +} + +func (r *reader) ResetPosition() { + r.line = -1 + r.head = 0 + r.lineOffset = -1 + r.AdvanceLine() +} + +func (r *reader) Source() []byte { + return r.source +} + +func (r *reader) Value(seg Segment) []byte { + return seg.Value(r.source) +} + +func (r *reader) Peek() byte { + if r.pos.Start >= 0 && r.pos.Start < r.sourceLength { + if r.pos.Padding != 0 { + return space[0] + } + return r.source[r.pos.Start] + } + return EOF +} + +func (r *reader) PeekLine() ([]byte, Segment) { + if r.pos.Start >= 0 && r.pos.Start < r.sourceLength { + if r.peekedLine == nil { + r.peekedLine = r.pos.Value(r.Source()) + } + return r.peekedLine, r.pos + } + return nil, r.pos +} + +// io.RuneReader interface +func (r *reader) ReadRune() (rune, int, error) { + return readRuneReader(r) +} + +func (r *reader) LineOffset() int { + if r.lineOffset < 0 { + v := 0 + for i := r.head; i < r.pos.Start; i++ { + if r.source[i] == '\t' { + v += util.TabWidth(v) + } else { + v++ + } + } + r.lineOffset = v - r.pos.Padding + } + return r.lineOffset +} + +func (r *reader) PrecendingCharacter() rune { + if r.pos.Start <= 0 { + if r.pos.Padding != 0 { + return rune(' ') + } + return rune('\n') + } + i := r.pos.Start - 1 + for ; i >= 0; i-- { + if utf8.RuneStart(r.source[i]) { + break + } + } + rn, _ := utf8.DecodeRune(r.source[i:]) + return rn +} + +func (r *reader) Advance(n int) { + r.lineOffset = -1 + if n < len(r.peekedLine) && r.pos.Padding == 0 { + r.pos.Start += n + r.peekedLine = nil + return + } + r.peekedLine = nil + l := r.sourceLength + for ; n > 0 && r.pos.Start < l; n-- { + if r.pos.Padding != 0 { + r.pos.Padding-- + continue + } + if r.source[r.pos.Start] == '\n' { + r.AdvanceLine() + continue + } + r.pos.Start++ + } +} + +func (r *reader) AdvanceAndSetPadding(n, padding int) { + r.Advance(n) + if padding > r.pos.Padding { + r.SetPadding(padding) + } +} + +func (r *reader) AdvanceLine() { + r.lineOffset = -1 + r.peekedLine = nil + r.pos.Start = r.pos.Stop + r.head = r.pos.Start + if r.pos.Start < 0 { + return + } + r.pos.Stop = r.sourceLength + for i := r.pos.Start; i < r.sourceLength; i++ { + c := r.source[i] + if c == '\n' { + r.pos.Stop = i + 1 + break + } + } + r.line++ + r.pos.Padding = 0 +} + +func (r *reader) Position() (int, Segment) { + return r.line, r.pos +} + +func (r *reader) SetPosition(line int, pos Segment) { + r.lineOffset = -1 + r.line = line + r.pos = pos +} + +func (r *reader) SetPadding(v int) { + r.pos.Padding = v +} + +func (r *reader) SkipSpaces() (Segment, int, bool) { + return skipSpacesReader(r) +} + +func (r *reader) SkipBlankLines() (Segment, int, bool) { + return skipBlankLinesReader(r) +} + +func (r *reader) Match(reg *regexp.Regexp) bool { + return matchReader(r, reg) +} + +func (r *reader) FindSubMatch(reg *regexp.Regexp) [][]byte { + return findSubMatchReader(r, reg) +} + +// A BlockReader interface is a reader that is optimized for Blocks. +type BlockReader interface { + Reader + // Reset resets current state and sets new segments to the reader. + Reset(segment *Segments) +} + +type blockReader struct { + source []byte + segments *Segments + segmentsLength int + line int + pos Segment + head int + last int + lineOffset int +} + +// NewBlockReader returns a new BlockReader. +func NewBlockReader(source []byte, segments *Segments) BlockReader { + r := &blockReader{ + source: source, + } + if segments != nil { + r.Reset(segments) + } + return r +} + +func (r *blockReader) ResetPosition() { + r.line = -1 + r.head = 0 + r.last = 0 + r.lineOffset = -1 + r.pos.Start = -1 + r.pos.Stop = -1 + r.pos.Padding = 0 + if r.segmentsLength > 0 { + last := r.segments.At(r.segmentsLength - 1) + r.last = last.Stop + } + r.AdvanceLine() +} + +func (r *blockReader) Reset(segments *Segments) { + r.segments = segments + r.segmentsLength = segments.Len() + r.ResetPosition() +} + +func (r *blockReader) Source() []byte { + return r.source +} + +func (r *blockReader) Value(seg Segment) []byte { + line := r.segmentsLength - 1 + ret := make([]byte, 0, seg.Stop-seg.Start+1) + for ; line >= 0; line-- { + if seg.Start >= r.segments.At(line).Start { + break + } + } + i := seg.Start + for ; line < r.segmentsLength; line++ { + s := r.segments.At(line) + if i < 0 { + i = s.Start + } + ret = s.ConcatPadding(ret) + for ; i < seg.Stop && i < s.Stop; i++ { + ret = append(ret, r.source[i]) + } + i = -1 + if s.Stop > seg.Stop { + break + } + } + return ret +} + +// io.RuneReader interface +func (r *blockReader) ReadRune() (rune, int, error) { + return readRuneReader(r) +} + +func (r *blockReader) PrecendingCharacter() rune { + if r.pos.Padding != 0 { + return rune(' ') + } + if r.segments.Len() < 1 { + return rune('\n') + } + firstSegment := r.segments.At(0) + if r.line == 0 && r.pos.Start <= firstSegment.Start { + return rune('\n') + } + l := len(r.source) + i := r.pos.Start - 1 + for ; i < l && i >= 0; i-- { + if utf8.RuneStart(r.source[i]) { + break + } + } + if i < 0 || i >= l { + return rune('\n') + } + rn, _ := utf8.DecodeRune(r.source[i:]) + return rn +} + +func (r *blockReader) LineOffset() int { + if r.lineOffset < 0 { + v := 0 + for i := r.head; i < r.pos.Start; i++ { + if r.source[i] == '\t' { + v += util.TabWidth(v) + } else { + v++ + } + } + r.lineOffset = v - r.pos.Padding + } + return r.lineOffset +} + +func (r *blockReader) Peek() byte { + if r.line < r.segmentsLength && r.pos.Start >= 0 && r.pos.Start < r.last { + if r.pos.Padding != 0 { + return space[0] + } + return r.source[r.pos.Start] + } + return EOF +} + +func (r *blockReader) PeekLine() ([]byte, Segment) { + if r.line < r.segmentsLength && r.pos.Start >= 0 && r.pos.Start < r.last { + return r.pos.Value(r.source), r.pos + } + return nil, r.pos +} + +func (r *blockReader) Advance(n int) { + r.lineOffset = -1 + + if n < r.pos.Stop-r.pos.Start && r.pos.Padding == 0 { + r.pos.Start += n + return + } + + for ; n > 0; n-- { + if r.pos.Padding != 0 { + r.pos.Padding-- + continue + } + if r.pos.Start >= r.pos.Stop-1 && r.pos.Stop < r.last { + r.AdvanceLine() + continue + } + r.pos.Start++ + } +} + +func (r *blockReader) AdvanceAndSetPadding(n, padding int) { + r.Advance(n) + if padding > r.pos.Padding { + r.SetPadding(padding) + } +} + +func (r *blockReader) AdvanceLine() { + r.SetPosition(r.line+1, NewSegment(invalidValue, invalidValue)) + r.head = r.pos.Start +} + +func (r *blockReader) Position() (int, Segment) { + return r.line, r.pos +} + +func (r *blockReader) SetPosition(line int, pos Segment) { + r.lineOffset = -1 + r.line = line + if pos.Start == invalidValue { + if r.line < r.segmentsLength { + s := r.segments.At(line) + r.head = s.Start + r.pos = s + } + } else { + r.pos = pos + if r.line < r.segmentsLength { + s := r.segments.At(line) + r.head = s.Start + } + } +} + +func (r *blockReader) SetPadding(v int) { + r.lineOffset = -1 + r.pos.Padding = v +} + +func (r *blockReader) SkipSpaces() (Segment, int, bool) { + return skipSpacesReader(r) +} + +func (r *blockReader) SkipBlankLines() (Segment, int, bool) { + return skipBlankLinesReader(r) +} + +func (r *blockReader) Match(reg *regexp.Regexp) bool { + return matchReader(r, reg) +} + +func (r *blockReader) FindSubMatch(reg *regexp.Regexp) [][]byte { + return findSubMatchReader(r, reg) +} + +func skipBlankLinesReader(r Reader) (Segment, int, bool) { + lines := 0 + for { + line, seg := r.PeekLine() + if line == nil { + return seg, lines, false + } + if util.IsBlank(line) { + lines++ + r.AdvanceLine() + } else { + return seg, lines, true + } + } +} + +func skipSpacesReader(r Reader) (Segment, int, bool) { + chars := 0 + for { + line, segment := r.PeekLine() + if line == nil { + return segment, chars, false + } + for i, c := range line { + if util.IsSpace(c) { + chars++ + r.Advance(1) + continue + } + return segment.WithStart(segment.Start + i + 1), chars, true + } + } +} + +func matchReader(r Reader, reg *regexp.Regexp) bool { + oldline, oldseg := r.Position() + match := reg.FindReaderSubmatchIndex(r) + r.SetPosition(oldline, oldseg) + if match == nil { + return false + } + r.Advance(match[1] - match[0]) + return true +} + +func findSubMatchReader(r Reader, reg *regexp.Regexp) [][]byte { + oldline, oldseg := r.Position() + match := reg.FindReaderSubmatchIndex(r) + r.SetPosition(oldline, oldseg) + if match == nil { + return nil + } + runes := make([]rune, 0, match[1]-match[0]) + for i := 0; i < match[1]; { + r, size, _ := readRuneReader(r) + i += size + runes = append(runes, r) + } + result := [][]byte{} + for i := 0; i < len(match); i += 2 { + result = append(result, []byte(string(runes[match[i]:match[i+1]]))) + } + + r.SetPosition(oldline, oldseg) + r.Advance(match[1] - match[0]) + return result +} + +func readRuneReader(r Reader) (rune, int, error) { + line, _ := r.PeekLine() + if line == nil { + return 0, 0, io.EOF + } + rn, size := utf8.DecodeRune(line) + if rn == utf8.RuneError { + return 0, 0, io.EOF + } + r.Advance(size) + return rn, size, nil +} diff --git a/vendor/github.com/yuin/goldmark/text/segment.go b/vendor/github.com/yuin/goldmark/text/segment.go new file mode 100644 index 0000000000..badd4bc8e8 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/text/segment.go @@ -0,0 +1,209 @@ +package text + +import ( + "bytes" + "github.com/yuin/goldmark/util" +) + +var space = []byte(" ") + +// A Segment struct holds information about source positions. +type Segment struct { + // Start is a start position of the segment. + Start int + + // Stop is a stop position of the segment. + // This value should be excluded. + Stop int + + // Padding is a padding length of the segment. + Padding int +} + +// NewSegment return a new Segment. +func NewSegment(start, stop int) Segment { + return Segment{ + Start: start, + Stop: stop, + Padding: 0, + } +} + +// NewSegmentPadding returns a new Segment with the given padding. +func NewSegmentPadding(start, stop, n int) Segment { + return Segment{ + Start: start, + Stop: stop, + Padding: n, + } +} + +// Value returns a value of the segment. +func (t *Segment) Value(buffer []byte) []byte { + if t.Padding == 0 { + return buffer[t.Start:t.Stop] + } + result := make([]byte, 0, t.Padding+t.Stop-t.Start+1) + result = append(result, bytes.Repeat(space, t.Padding)...) + return append(result, buffer[t.Start:t.Stop]...) +} + +// Len returns a length of the segment. +func (t *Segment) Len() int { + return t.Stop - t.Start + t.Padding +} + +// Between returns a segment between this segment and the given segment. +func (t *Segment) Between(other Segment) Segment { + if t.Stop != other.Stop { + panic("invalid state") + } + return NewSegmentPadding( + t.Start, + other.Start, + t.Padding-other.Padding, + ) +} + +// IsEmpty returns true if this segment is empty, otherwise false. +func (t *Segment) IsEmpty() bool { + return t.Start >= t.Stop && t.Padding == 0 +} + +// TrimRightSpace returns a new segment by slicing off all trailing +// space characters. +func (t *Segment) TrimRightSpace(buffer []byte) Segment { + v := buffer[t.Start:t.Stop] + l := util.TrimRightSpaceLength(v) + if l == len(v) { + return NewSegment(t.Start, t.Start) + } + return NewSegmentPadding(t.Start, t.Stop-l, t.Padding) +} + +// TrimLeftSpace returns a new segment by slicing off all leading +// space characters including padding. +func (t *Segment) TrimLeftSpace(buffer []byte) Segment { + v := buffer[t.Start:t.Stop] + l := util.TrimLeftSpaceLength(v) + return NewSegment(t.Start+l, t.Stop) +} + +// TrimLeftSpaceWidth returns a new segment by slicing off leading space +// characters until the given width. +func (t *Segment) TrimLeftSpaceWidth(width int, buffer []byte) Segment { + padding := t.Padding + for ; width > 0; width-- { + if padding == 0 { + break + } + padding-- + } + if width == 0 { + return NewSegmentPadding(t.Start, t.Stop, padding) + } + text := buffer[t.Start:t.Stop] + start := t.Start + for _, c := range text { + if start >= t.Stop-1 || width <= 0 { + break + } + if c == ' ' { + width-- + } else if c == '\t' { + width -= 4 + } else { + break + } + start++ + } + if width < 0 { + padding = width * -1 + } + return NewSegmentPadding(start, t.Stop, padding) +} + +// WithStart returns a new Segment with same value except Start. +func (t *Segment) WithStart(v int) Segment { + return NewSegmentPadding(v, t.Stop, t.Padding) +} + +// WithStop returns a new Segment with same value except Stop. +func (t *Segment) WithStop(v int) Segment { + return NewSegmentPadding(t.Start, v, t.Padding) +} + +// ConcatPadding concats the padding to the given slice. +func (t *Segment) ConcatPadding(v []byte) []byte { + if t.Padding > 0 { + return append(v, bytes.Repeat(space, t.Padding)...) + } + return v +} + +// Segments is a collection of the Segment. +type Segments struct { + values []Segment +} + +// NewSegments return a new Segments. +func NewSegments() *Segments { + return &Segments{ + values: nil, + } +} + +// Append appends the given segment after the tail of the collection. +func (s *Segments) Append(t Segment) { + if s.values == nil { + s.values = make([]Segment, 0, 20) + } + s.values = append(s.values, t) +} + +// AppendAll appends all elements of given segments after the tail of the collection. +func (s *Segments) AppendAll(t []Segment) { + if s.values == nil { + s.values = make([]Segment, 0, 20) + } + s.values = append(s.values, t...) +} + +// Len returns the length of the collection. +func (s *Segments) Len() int { + if s.values == nil { + return 0 + } + return len(s.values) +} + +// At returns a segment at the given index. +func (s *Segments) At(i int) Segment { + return s.values[i] +} + +// Set sets the given Segment. +func (s *Segments) Set(i int, v Segment) { + s.values[i] = v +} + +// SetSliced replace the collection with a subsliced value. +func (s *Segments) SetSliced(lo, hi int) { + s.values = s.values[lo:hi] +} + +// Sliced returns a subslice of the collection. +func (s *Segments) Sliced(lo, hi int) []Segment { + return s.values[lo:hi] +} + +// Clear delete all element of the collection. +func (s *Segments) Clear() { + s.values = nil +} + +// Unshift insert the given Segment to head of the collection. +func (s *Segments) Unshift(v Segment) { + s.values = append(s.values[0:1], s.values[0:]...) + s.values[0] = v +} diff --git a/vendor/github.com/yuin/goldmark/util/html5entities.go b/vendor/github.com/yuin/goldmark/util/html5entities.go new file mode 100644 index 0000000000..b8e00a91b7 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/util/html5entities.go @@ -0,0 +1,2142 @@ +package util + +// An HTML5Entity struct represents HTML5 entitites. +type HTML5Entity struct { + Name string + CodePoints []int + Characters []byte +} + +// LookUpHTML5EntityByName returns (an HTML5Entity, true) if an entity named +// given name is found, otherwise (nil, false) +func LookUpHTML5EntityByName(name string) (*HTML5Entity, bool) { + v, ok := html5entities[name] + return v, ok +} + +var html5entities = map[string]*HTML5Entity{ + "AElig": {Name: "AElig", CodePoints: []int{198}, Characters: []byte{0xc3, 0x86}}, + "AMP": {Name: "AMP", CodePoints: []int{38}, Characters: []byte{0x26}}, + "Aacute": {Name: "Aacute", CodePoints: []int{193}, Characters: []byte{0xc3, 0x81}}, + "Acirc": {Name: "Acirc", CodePoints: []int{194}, Characters: []byte{0xc3, 0x82}}, + "Acy": {Name: "Acy", CodePoints: []int{1040}, Characters: []byte{0xd0, 0x90}}, + "Afr": {Name: "Afr", CodePoints: []int{120068}, Characters: []byte{0xf0, 0x9d, 0x94, 0x84}}, + "Agrave": {Name: "Agrave", CodePoints: []int{192}, Characters: []byte{0xc3, 0x80}}, + "Alpha": {Name: "Alpha", CodePoints: []int{913}, Characters: []byte{0xce, 0x91}}, + "Amacr": {Name: "Amacr", CodePoints: []int{256}, Characters: []byte{0xc4, 0x80}}, + "And": {Name: "And", CodePoints: []int{10835}, Characters: []byte{0xe2, 0xa9, 0x93}}, + "Aogon": {Name: "Aogon", CodePoints: []int{260}, Characters: []byte{0xc4, 0x84}}, + "Aopf": {Name: "Aopf", CodePoints: []int{120120}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb8}}, + "ApplyFunction": {Name: "ApplyFunction", CodePoints: []int{8289}, Characters: []byte{0xe2, 0x81, 0xa1}}, + "Aring": {Name: "Aring", CodePoints: []int{197}, Characters: []byte{0xc3, 0x85}}, + "Ascr": {Name: "Ascr", CodePoints: []int{119964}, Characters: []byte{0xf0, 0x9d, 0x92, 0x9c}}, + "Assign": {Name: "Assign", CodePoints: []int{8788}, Characters: []byte{0xe2, 0x89, 0x94}}, + "Atilde": {Name: "Atilde", CodePoints: []int{195}, Characters: []byte{0xc3, 0x83}}, + "Auml": {Name: "Auml", CodePoints: []int{196}, Characters: []byte{0xc3, 0x84}}, + "Backslash": {Name: "Backslash", CodePoints: []int{8726}, Characters: []byte{0xe2, 0x88, 0x96}}, + "Barv": {Name: "Barv", CodePoints: []int{10983}, Characters: []byte{0xe2, 0xab, 0xa7}}, + "Barwed": {Name: "Barwed", CodePoints: []int{8966}, Characters: []byte{0xe2, 0x8c, 0x86}}, + "Bcy": {Name: "Bcy", CodePoints: []int{1041}, Characters: []byte{0xd0, 0x91}}, + "Because": {Name: "Because", CodePoints: []int{8757}, Characters: []byte{0xe2, 0x88, 0xb5}}, + "Bernoullis": {Name: "Bernoullis", CodePoints: []int{8492}, Characters: []byte{0xe2, 0x84, 0xac}}, + "Beta": {Name: "Beta", CodePoints: []int{914}, Characters: []byte{0xce, 0x92}}, + "Bfr": {Name: "Bfr", CodePoints: []int{120069}, Characters: []byte{0xf0, 0x9d, 0x94, 0x85}}, + "Bopf": {Name: "Bopf", CodePoints: []int{120121}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb9}}, + "Breve": {Name: "Breve", CodePoints: []int{728}, Characters: []byte{0xcb, 0x98}}, + "Bscr": {Name: "Bscr", CodePoints: []int{8492}, Characters: []byte{0xe2, 0x84, 0xac}}, + "Bumpeq": {Name: "Bumpeq", CodePoints: []int{8782}, Characters: []byte{0xe2, 0x89, 0x8e}}, + "CHcy": {Name: "CHcy", CodePoints: []int{1063}, Characters: []byte{0xd0, 0xa7}}, + "COPY": {Name: "COPY", CodePoints: []int{169}, Characters: []byte{0xc2, 0xa9}}, + "Cacute": {Name: "Cacute", CodePoints: []int{262}, Characters: []byte{0xc4, 0x86}}, + "Cap": {Name: "Cap", CodePoints: []int{8914}, Characters: []byte{0xe2, 0x8b, 0x92}}, + "CapitalDifferentialD": {Name: "CapitalDifferentialD", CodePoints: []int{8517}, Characters: []byte{0xe2, 0x85, 0x85}}, + "Cayleys": {Name: "Cayleys", CodePoints: []int{8493}, Characters: []byte{0xe2, 0x84, 0xad}}, + "Ccaron": {Name: "Ccaron", CodePoints: []int{268}, Characters: []byte{0xc4, 0x8c}}, + "Ccedil": {Name: "Ccedil", CodePoints: []int{199}, Characters: []byte{0xc3, 0x87}}, + "Ccirc": {Name: "Ccirc", CodePoints: []int{264}, Characters: []byte{0xc4, 0x88}}, + "Cconint": {Name: "Cconint", CodePoints: []int{8752}, Characters: []byte{0xe2, 0x88, 0xb0}}, + "Cdot": {Name: "Cdot", CodePoints: []int{266}, Characters: []byte{0xc4, 0x8a}}, + "Cedilla": {Name: "Cedilla", CodePoints: []int{184}, Characters: []byte{0xc2, 0xb8}}, + "CenterDot": {Name: "CenterDot", CodePoints: []int{183}, Characters: []byte{0xc2, 0xb7}}, + "Cfr": {Name: "Cfr", CodePoints: []int{8493}, Characters: []byte{0xe2, 0x84, 0xad}}, + "Chi": {Name: "Chi", CodePoints: []int{935}, Characters: []byte{0xce, 0xa7}}, + "CircleDot": {Name: "CircleDot", CodePoints: []int{8857}, Characters: []byte{0xe2, 0x8a, 0x99}}, + "CircleMinus": {Name: "CircleMinus", CodePoints: []int{8854}, Characters: []byte{0xe2, 0x8a, 0x96}}, + "CirclePlus": {Name: "CirclePlus", CodePoints: []int{8853}, Characters: []byte{0xe2, 0x8a, 0x95}}, + "CircleTimes": {Name: "CircleTimes", CodePoints: []int{8855}, Characters: []byte{0xe2, 0x8a, 0x97}}, + "ClockwiseContourIntegral": {Name: "ClockwiseContourIntegral", CodePoints: []int{8754}, Characters: []byte{0xe2, 0x88, 0xb2}}, + "CloseCurlyDoubleQuote": {Name: "CloseCurlyDoubleQuote", CodePoints: []int{8221}, Characters: []byte{0xe2, 0x80, 0x9d}}, + "CloseCurlyQuote": {Name: "CloseCurlyQuote", CodePoints: []int{8217}, Characters: []byte{0xe2, 0x80, 0x99}}, + "Colon": {Name: "Colon", CodePoints: []int{8759}, Characters: []byte{0xe2, 0x88, 0xb7}}, + "Colone": {Name: "Colone", CodePoints: []int{10868}, Characters: []byte{0xe2, 0xa9, 0xb4}}, + "Congruent": {Name: "Congruent", CodePoints: []int{8801}, Characters: []byte{0xe2, 0x89, 0xa1}}, + "Conint": {Name: "Conint", CodePoints: []int{8751}, Characters: []byte{0xe2, 0x88, 0xaf}}, + "ContourIntegral": {Name: "ContourIntegral", CodePoints: []int{8750}, Characters: []byte{0xe2, 0x88, 0xae}}, + "Copf": {Name: "Copf", CodePoints: []int{8450}, Characters: []byte{0xe2, 0x84, 0x82}}, + "Coproduct": {Name: "Coproduct", CodePoints: []int{8720}, Characters: []byte{0xe2, 0x88, 0x90}}, + "CounterClockwiseContourIntegral": {Name: "CounterClockwiseContourIntegral", CodePoints: []int{8755}, Characters: []byte{0xe2, 0x88, 0xb3}}, + "Cross": {Name: "Cross", CodePoints: []int{10799}, Characters: []byte{0xe2, 0xa8, 0xaf}}, + "Cscr": {Name: "Cscr", CodePoints: []int{119966}, Characters: []byte{0xf0, 0x9d, 0x92, 0x9e}}, + "Cup": {Name: "Cup", CodePoints: []int{8915}, Characters: []byte{0xe2, 0x8b, 0x93}}, + "CupCap": {Name: "CupCap", CodePoints: []int{8781}, Characters: []byte{0xe2, 0x89, 0x8d}}, + "DD": {Name: "DD", CodePoints: []int{8517}, Characters: []byte{0xe2, 0x85, 0x85}}, + "DDotrahd": {Name: "DDotrahd", CodePoints: []int{10513}, Characters: []byte{0xe2, 0xa4, 0x91}}, + "DJcy": {Name: "DJcy", CodePoints: []int{1026}, Characters: []byte{0xd0, 0x82}}, + "DScy": {Name: "DScy", CodePoints: []int{1029}, Characters: []byte{0xd0, 0x85}}, + "DZcy": {Name: "DZcy", CodePoints: []int{1039}, Characters: []byte{0xd0, 0x8f}}, + "Dagger": {Name: "Dagger", CodePoints: []int{8225}, Characters: []byte{0xe2, 0x80, 0xa1}}, + "Darr": {Name: "Darr", CodePoints: []int{8609}, Characters: []byte{0xe2, 0x86, 0xa1}}, + "Dashv": {Name: "Dashv", CodePoints: []int{10980}, Characters: []byte{0xe2, 0xab, 0xa4}}, + "Dcaron": {Name: "Dcaron", CodePoints: []int{270}, Characters: []byte{0xc4, 0x8e}}, + "Dcy": {Name: "Dcy", CodePoints: []int{1044}, Characters: []byte{0xd0, 0x94}}, + "Del": {Name: "Del", CodePoints: []int{8711}, Characters: []byte{0xe2, 0x88, 0x87}}, + "Delta": {Name: "Delta", CodePoints: []int{916}, Characters: []byte{0xce, 0x94}}, + "Dfr": {Name: "Dfr", CodePoints: []int{120071}, Characters: []byte{0xf0, 0x9d, 0x94, 0x87}}, + "DiacriticalAcute": {Name: "DiacriticalAcute", CodePoints: []int{180}, Characters: []byte{0xc2, 0xb4}}, + "DiacriticalDot": {Name: "DiacriticalDot", CodePoints: []int{729}, Characters: []byte{0xcb, 0x99}}, + "DiacriticalDoubleAcute": {Name: "DiacriticalDoubleAcute", CodePoints: []int{733}, Characters: []byte{0xcb, 0x9d}}, + "DiacriticalGrave": {Name: "DiacriticalGrave", CodePoints: []int{96}, Characters: []byte{0x60}}, + "DiacriticalTilde": {Name: "DiacriticalTilde", CodePoints: []int{732}, Characters: []byte{0xcb, 0x9c}}, + "Diamond": {Name: "Diamond", CodePoints: []int{8900}, Characters: []byte{0xe2, 0x8b, 0x84}}, + "DifferentialD": {Name: "DifferentialD", CodePoints: []int{8518}, Characters: []byte{0xe2, 0x85, 0x86}}, + "Dopf": {Name: "Dopf", CodePoints: []int{120123}, Characters: []byte{0xf0, 0x9d, 0x94, 0xbb}}, + "Dot": {Name: "Dot", CodePoints: []int{168}, Characters: []byte{0xc2, 0xa8}}, + "DotDot": {Name: "DotDot", CodePoints: []int{8412}, Characters: []byte{0xe2, 0x83, 0x9c}}, + "DotEqual": {Name: "DotEqual", CodePoints: []int{8784}, Characters: []byte{0xe2, 0x89, 0x90}}, + "DoubleContourIntegral": {Name: "DoubleContourIntegral", CodePoints: []int{8751}, Characters: []byte{0xe2, 0x88, 0xaf}}, + "DoubleDot": {Name: "DoubleDot", CodePoints: []int{168}, Characters: []byte{0xc2, 0xa8}}, + "DoubleDownArrow": {Name: "DoubleDownArrow", CodePoints: []int{8659}, Characters: []byte{0xe2, 0x87, 0x93}}, + "DoubleLeftArrow": {Name: "DoubleLeftArrow", CodePoints: []int{8656}, Characters: []byte{0xe2, 0x87, 0x90}}, + "DoubleLeftRightArrow": {Name: "DoubleLeftRightArrow", CodePoints: []int{8660}, Characters: []byte{0xe2, 0x87, 0x94}}, + "DoubleLeftTee": {Name: "DoubleLeftTee", CodePoints: []int{10980}, Characters: []byte{0xe2, 0xab, 0xa4}}, + "DoubleLongLeftArrow": {Name: "DoubleLongLeftArrow", CodePoints: []int{10232}, Characters: []byte{0xe2, 0x9f, 0xb8}}, + "DoubleLongLeftRightArrow": {Name: "DoubleLongLeftRightArrow", CodePoints: []int{10234}, Characters: []byte{0xe2, 0x9f, 0xba}}, + "DoubleLongRightArrow": {Name: "DoubleLongRightArrow", CodePoints: []int{10233}, Characters: []byte{0xe2, 0x9f, 0xb9}}, + "DoubleRightArrow": {Name: "DoubleRightArrow", CodePoints: []int{8658}, Characters: []byte{0xe2, 0x87, 0x92}}, + "DoubleRightTee": {Name: "DoubleRightTee", CodePoints: []int{8872}, Characters: []byte{0xe2, 0x8a, 0xa8}}, + "DoubleUpArrow": {Name: "DoubleUpArrow", CodePoints: []int{8657}, Characters: []byte{0xe2, 0x87, 0x91}}, + "DoubleUpDownArrow": {Name: "DoubleUpDownArrow", CodePoints: []int{8661}, Characters: []byte{0xe2, 0x87, 0x95}}, + "DoubleVerticalBar": {Name: "DoubleVerticalBar", CodePoints: []int{8741}, Characters: []byte{0xe2, 0x88, 0xa5}}, + "DownArrow": {Name: "DownArrow", CodePoints: []int{8595}, Characters: []byte{0xe2, 0x86, 0x93}}, + "DownArrowBar": {Name: "DownArrowBar", CodePoints: []int{10515}, Characters: []byte{0xe2, 0xa4, 0x93}}, + "DownArrowUpArrow": {Name: "DownArrowUpArrow", CodePoints: []int{8693}, Characters: []byte{0xe2, 0x87, 0xb5}}, + "DownBreve": {Name: "DownBreve", CodePoints: []int{785}, Characters: []byte{0xcc, 0x91}}, + "DownLeftRightVector": {Name: "DownLeftRightVector", CodePoints: []int{10576}, Characters: []byte{0xe2, 0xa5, 0x90}}, + "DownLeftTeeVector": {Name: "DownLeftTeeVector", CodePoints: []int{10590}, Characters: []byte{0xe2, 0xa5, 0x9e}}, + "DownLeftVector": {Name: "DownLeftVector", CodePoints: []int{8637}, Characters: []byte{0xe2, 0x86, 0xbd}}, + "DownLeftVectorBar": {Name: "DownLeftVectorBar", CodePoints: []int{10582}, Characters: []byte{0xe2, 0xa5, 0x96}}, + "DownRightTeeVector": {Name: "DownRightTeeVector", CodePoints: []int{10591}, Characters: []byte{0xe2, 0xa5, 0x9f}}, + "DownRightVector": {Name: "DownRightVector", CodePoints: []int{8641}, Characters: []byte{0xe2, 0x87, 0x81}}, + "DownRightVectorBar": {Name: "DownRightVectorBar", CodePoints: []int{10583}, Characters: []byte{0xe2, 0xa5, 0x97}}, + "DownTee": {Name: "DownTee", CodePoints: []int{8868}, Characters: []byte{0xe2, 0x8a, 0xa4}}, + "DownTeeArrow": {Name: "DownTeeArrow", CodePoints: []int{8615}, Characters: []byte{0xe2, 0x86, 0xa7}}, + "Downarrow": {Name: "Downarrow", CodePoints: []int{8659}, Characters: []byte{0xe2, 0x87, 0x93}}, + "Dscr": {Name: "Dscr", CodePoints: []int{119967}, Characters: []byte{0xf0, 0x9d, 0x92, 0x9f}}, + "Dstrok": {Name: "Dstrok", CodePoints: []int{272}, Characters: []byte{0xc4, 0x90}}, + "ENG": {Name: "ENG", CodePoints: []int{330}, Characters: []byte{0xc5, 0x8a}}, + "ETH": {Name: "ETH", CodePoints: []int{208}, Characters: []byte{0xc3, 0x90}}, + "Eacute": {Name: "Eacute", CodePoints: []int{201}, Characters: []byte{0xc3, 0x89}}, + "Ecaron": {Name: "Ecaron", CodePoints: []int{282}, Characters: []byte{0xc4, 0x9a}}, + "Ecirc": {Name: "Ecirc", CodePoints: []int{202}, Characters: []byte{0xc3, 0x8a}}, + "Ecy": {Name: "Ecy", CodePoints: []int{1069}, Characters: []byte{0xd0, 0xad}}, + "Edot": {Name: "Edot", CodePoints: []int{278}, Characters: []byte{0xc4, 0x96}}, + "Efr": {Name: "Efr", CodePoints: []int{120072}, Characters: []byte{0xf0, 0x9d, 0x94, 0x88}}, + "Egrave": {Name: "Egrave", CodePoints: []int{200}, Characters: []byte{0xc3, 0x88}}, + "Element": {Name: "Element", CodePoints: []int{8712}, Characters: []byte{0xe2, 0x88, 0x88}}, + "Emacr": {Name: "Emacr", CodePoints: []int{274}, Characters: []byte{0xc4, 0x92}}, + "EmptySmallSquare": {Name: "EmptySmallSquare", CodePoints: []int{9723}, Characters: []byte{0xe2, 0x97, 0xbb}}, + "EmptyVerySmallSquare": {Name: "EmptyVerySmallSquare", CodePoints: []int{9643}, Characters: []byte{0xe2, 0x96, 0xab}}, + "Eogon": {Name: "Eogon", CodePoints: []int{280}, Characters: []byte{0xc4, 0x98}}, + "Eopf": {Name: "Eopf", CodePoints: []int{120124}, Characters: []byte{0xf0, 0x9d, 0x94, 0xbc}}, + "Epsilon": {Name: "Epsilon", CodePoints: []int{917}, Characters: []byte{0xce, 0x95}}, + "Equal": {Name: "Equal", CodePoints: []int{10869}, Characters: []byte{0xe2, 0xa9, 0xb5}}, + "EqualTilde": {Name: "EqualTilde", CodePoints: []int{8770}, Characters: []byte{0xe2, 0x89, 0x82}}, + "Equilibrium": {Name: "Equilibrium", CodePoints: []int{8652}, Characters: []byte{0xe2, 0x87, 0x8c}}, + "Escr": {Name: "Escr", CodePoints: []int{8496}, Characters: []byte{0xe2, 0x84, 0xb0}}, + "Esim": {Name: "Esim", CodePoints: []int{10867}, Characters: []byte{0xe2, 0xa9, 0xb3}}, + "Eta": {Name: "Eta", CodePoints: []int{919}, Characters: []byte{0xce, 0x97}}, + "Euml": {Name: "Euml", CodePoints: []int{203}, Characters: []byte{0xc3, 0x8b}}, + "Exists": {Name: "Exists", CodePoints: []int{8707}, Characters: []byte{0xe2, 0x88, 0x83}}, + "ExponentialE": {Name: "ExponentialE", CodePoints: []int{8519}, Characters: []byte{0xe2, 0x85, 0x87}}, + "Fcy": {Name: "Fcy", CodePoints: []int{1060}, Characters: []byte{0xd0, 0xa4}}, + "Ffr": {Name: "Ffr", CodePoints: []int{120073}, Characters: []byte{0xf0, 0x9d, 0x94, 0x89}}, + "FilledSmallSquare": {Name: "FilledSmallSquare", CodePoints: []int{9724}, Characters: []byte{0xe2, 0x97, 0xbc}}, + "FilledVerySmallSquare": {Name: "FilledVerySmallSquare", CodePoints: []int{9642}, Characters: []byte{0xe2, 0x96, 0xaa}}, + "Fopf": {Name: "Fopf", CodePoints: []int{120125}, Characters: []byte{0xf0, 0x9d, 0x94, 0xbd}}, + "ForAll": {Name: "ForAll", CodePoints: []int{8704}, Characters: []byte{0xe2, 0x88, 0x80}}, + "Fouriertrf": {Name: "Fouriertrf", CodePoints: []int{8497}, Characters: []byte{0xe2, 0x84, 0xb1}}, + "Fscr": {Name: "Fscr", CodePoints: []int{8497}, Characters: []byte{0xe2, 0x84, 0xb1}}, + "GJcy": {Name: "GJcy", CodePoints: []int{1027}, Characters: []byte{0xd0, 0x83}}, + "GT": {Name: "GT", CodePoints: []int{62}, Characters: []byte{0x3e}}, + "Gamma": {Name: "Gamma", CodePoints: []int{915}, Characters: []byte{0xce, 0x93}}, + "Gammad": {Name: "Gammad", CodePoints: []int{988}, Characters: []byte{0xcf, 0x9c}}, + "Gbreve": {Name: "Gbreve", CodePoints: []int{286}, Characters: []byte{0xc4, 0x9e}}, + "Gcedil": {Name: "Gcedil", CodePoints: []int{290}, Characters: []byte{0xc4, 0xa2}}, + "Gcirc": {Name: "Gcirc", CodePoints: []int{284}, Characters: []byte{0xc4, 0x9c}}, + "Gcy": {Name: "Gcy", CodePoints: []int{1043}, Characters: []byte{0xd0, 0x93}}, + "Gdot": {Name: "Gdot", CodePoints: []int{288}, Characters: []byte{0xc4, 0xa0}}, + "Gfr": {Name: "Gfr", CodePoints: []int{120074}, Characters: []byte{0xf0, 0x9d, 0x94, 0x8a}}, + "Gg": {Name: "Gg", CodePoints: []int{8921}, Characters: []byte{0xe2, 0x8b, 0x99}}, + "Gopf": {Name: "Gopf", CodePoints: []int{120126}, Characters: []byte{0xf0, 0x9d, 0x94, 0xbe}}, + "GreaterEqual": {Name: "GreaterEqual", CodePoints: []int{8805}, Characters: []byte{0xe2, 0x89, 0xa5}}, + "GreaterEqualLess": {Name: "GreaterEqualLess", CodePoints: []int{8923}, Characters: []byte{0xe2, 0x8b, 0x9b}}, + "GreaterFullEqual": {Name: "GreaterFullEqual", CodePoints: []int{8807}, Characters: []byte{0xe2, 0x89, 0xa7}}, + "GreaterGreater": {Name: "GreaterGreater", CodePoints: []int{10914}, Characters: []byte{0xe2, 0xaa, 0xa2}}, + "GreaterLess": {Name: "GreaterLess", CodePoints: []int{8823}, Characters: []byte{0xe2, 0x89, 0xb7}}, + "GreaterSlantEqual": {Name: "GreaterSlantEqual", CodePoints: []int{10878}, Characters: []byte{0xe2, 0xa9, 0xbe}}, + "GreaterTilde": {Name: "GreaterTilde", CodePoints: []int{8819}, Characters: []byte{0xe2, 0x89, 0xb3}}, + "Gscr": {Name: "Gscr", CodePoints: []int{119970}, Characters: []byte{0xf0, 0x9d, 0x92, 0xa2}}, + "Gt": {Name: "Gt", CodePoints: []int{8811}, Characters: []byte{0xe2, 0x89, 0xab}}, + "HARDcy": {Name: "HARDcy", CodePoints: []int{1066}, Characters: []byte{0xd0, 0xaa}}, + "Hacek": {Name: "Hacek", CodePoints: []int{711}, Characters: []byte{0xcb, 0x87}}, + "Hat": {Name: "Hat", CodePoints: []int{94}, Characters: []byte{0x5e}}, + "Hcirc": {Name: "Hcirc", CodePoints: []int{292}, Characters: []byte{0xc4, 0xa4}}, + "Hfr": {Name: "Hfr", CodePoints: []int{8460}, Characters: []byte{0xe2, 0x84, 0x8c}}, + "HilbertSpace": {Name: "HilbertSpace", CodePoints: []int{8459}, Characters: []byte{0xe2, 0x84, 0x8b}}, + "Hopf": {Name: "Hopf", CodePoints: []int{8461}, Characters: []byte{0xe2, 0x84, 0x8d}}, + "HorizontalLine": {Name: "HorizontalLine", CodePoints: []int{9472}, Characters: []byte{0xe2, 0x94, 0x80}}, + "Hscr": {Name: "Hscr", CodePoints: []int{8459}, Characters: []byte{0xe2, 0x84, 0x8b}}, + "Hstrok": {Name: "Hstrok", CodePoints: []int{294}, Characters: []byte{0xc4, 0xa6}}, + "HumpDownHump": {Name: "HumpDownHump", CodePoints: []int{8782}, Characters: []byte{0xe2, 0x89, 0x8e}}, + "HumpEqual": {Name: "HumpEqual", CodePoints: []int{8783}, Characters: []byte{0xe2, 0x89, 0x8f}}, + "IEcy": {Name: "IEcy", CodePoints: []int{1045}, Characters: []byte{0xd0, 0x95}}, + "IJlig": {Name: "IJlig", CodePoints: []int{306}, Characters: []byte{0xc4, 0xb2}}, + "IOcy": {Name: "IOcy", CodePoints: []int{1025}, Characters: []byte{0xd0, 0x81}}, + "Iacute": {Name: "Iacute", CodePoints: []int{205}, Characters: []byte{0xc3, 0x8d}}, + "Icirc": {Name: "Icirc", CodePoints: []int{206}, Characters: []byte{0xc3, 0x8e}}, + "Icy": {Name: "Icy", CodePoints: []int{1048}, Characters: []byte{0xd0, 0x98}}, + "Idot": {Name: "Idot", CodePoints: []int{304}, Characters: []byte{0xc4, 0xb0}}, + "Ifr": {Name: "Ifr", CodePoints: []int{8465}, Characters: []byte{0xe2, 0x84, 0x91}}, + "Igrave": {Name: "Igrave", CodePoints: []int{204}, Characters: []byte{0xc3, 0x8c}}, + "Im": {Name: "Im", CodePoints: []int{8465}, Characters: []byte{0xe2, 0x84, 0x91}}, + "Imacr": {Name: "Imacr", CodePoints: []int{298}, Characters: []byte{0xc4, 0xaa}}, + "ImaginaryI": {Name: "ImaginaryI", CodePoints: []int{8520}, Characters: []byte{0xe2, 0x85, 0x88}}, + "Implies": {Name: "Implies", CodePoints: []int{8658}, Characters: []byte{0xe2, 0x87, 0x92}}, + "Int": {Name: "Int", CodePoints: []int{8748}, Characters: []byte{0xe2, 0x88, 0xac}}, + "Integral": {Name: "Integral", CodePoints: []int{8747}, Characters: []byte{0xe2, 0x88, 0xab}}, + "Intersection": {Name: "Intersection", CodePoints: []int{8898}, Characters: []byte{0xe2, 0x8b, 0x82}}, + "InvisibleComma": {Name: "InvisibleComma", CodePoints: []int{8291}, Characters: []byte{0xe2, 0x81, 0xa3}}, + "InvisibleTimes": {Name: "InvisibleTimes", CodePoints: []int{8290}, Characters: []byte{0xe2, 0x81, 0xa2}}, + "Iogon": {Name: "Iogon", CodePoints: []int{302}, Characters: []byte{0xc4, 0xae}}, + "Iopf": {Name: "Iopf", CodePoints: []int{120128}, Characters: []byte{0xf0, 0x9d, 0x95, 0x80}}, + "Iota": {Name: "Iota", CodePoints: []int{921}, Characters: []byte{0xce, 0x99}}, + "Iscr": {Name: "Iscr", CodePoints: []int{8464}, Characters: []byte{0xe2, 0x84, 0x90}}, + "Itilde": {Name: "Itilde", CodePoints: []int{296}, Characters: []byte{0xc4, 0xa8}}, + "Iukcy": {Name: "Iukcy", CodePoints: []int{1030}, Characters: []byte{0xd0, 0x86}}, + "Iuml": {Name: "Iuml", CodePoints: []int{207}, Characters: []byte{0xc3, 0x8f}}, + "Jcirc": {Name: "Jcirc", CodePoints: []int{308}, Characters: []byte{0xc4, 0xb4}}, + "Jcy": {Name: "Jcy", CodePoints: []int{1049}, Characters: []byte{0xd0, 0x99}}, + "Jfr": {Name: "Jfr", CodePoints: []int{120077}, Characters: []byte{0xf0, 0x9d, 0x94, 0x8d}}, + "Jopf": {Name: "Jopf", CodePoints: []int{120129}, Characters: []byte{0xf0, 0x9d, 0x95, 0x81}}, + "Jscr": {Name: "Jscr", CodePoints: []int{119973}, Characters: []byte{0xf0, 0x9d, 0x92, 0xa5}}, + "Jsercy": {Name: "Jsercy", CodePoints: []int{1032}, Characters: []byte{0xd0, 0x88}}, + "Jukcy": {Name: "Jukcy", CodePoints: []int{1028}, Characters: []byte{0xd0, 0x84}}, + "KHcy": {Name: "KHcy", CodePoints: []int{1061}, Characters: []byte{0xd0, 0xa5}}, + "KJcy": {Name: "KJcy", CodePoints: []int{1036}, Characters: []byte{0xd0, 0x8c}}, + "Kappa": {Name: "Kappa", CodePoints: []int{922}, Characters: []byte{0xce, 0x9a}}, + "Kcedil": {Name: "Kcedil", CodePoints: []int{310}, Characters: []byte{0xc4, 0xb6}}, + "Kcy": {Name: "Kcy", CodePoints: []int{1050}, Characters: []byte{0xd0, 0x9a}}, + "Kfr": {Name: "Kfr", CodePoints: []int{120078}, Characters: []byte{0xf0, 0x9d, 0x94, 0x8e}}, + "Kopf": {Name: "Kopf", CodePoints: []int{120130}, Characters: []byte{0xf0, 0x9d, 0x95, 0x82}}, + "Kscr": {Name: "Kscr", CodePoints: []int{119974}, Characters: []byte{0xf0, 0x9d, 0x92, 0xa6}}, + "LJcy": {Name: "LJcy", CodePoints: []int{1033}, Characters: []byte{0xd0, 0x89}}, + "LT": {Name: "LT", CodePoints: []int{60}, Characters: []byte{0x3c}}, + "Lacute": {Name: "Lacute", CodePoints: []int{313}, Characters: []byte{0xc4, 0xb9}}, + "Lambda": {Name: "Lambda", CodePoints: []int{923}, Characters: []byte{0xce, 0x9b}}, + "Lang": {Name: "Lang", CodePoints: []int{10218}, Characters: []byte{0xe2, 0x9f, 0xaa}}, + "Laplacetrf": {Name: "Laplacetrf", CodePoints: []int{8466}, Characters: []byte{0xe2, 0x84, 0x92}}, + "Larr": {Name: "Larr", CodePoints: []int{8606}, Characters: []byte{0xe2, 0x86, 0x9e}}, + "Lcaron": {Name: "Lcaron", CodePoints: []int{317}, Characters: []byte{0xc4, 0xbd}}, + "Lcedil": {Name: "Lcedil", CodePoints: []int{315}, Characters: []byte{0xc4, 0xbb}}, + "Lcy": {Name: "Lcy", CodePoints: []int{1051}, Characters: []byte{0xd0, 0x9b}}, + "LeftAngleBracket": {Name: "LeftAngleBracket", CodePoints: []int{10216}, Characters: []byte{0xe2, 0x9f, 0xa8}}, + "LeftArrow": {Name: "LeftArrow", CodePoints: []int{8592}, Characters: []byte{0xe2, 0x86, 0x90}}, + "LeftArrowBar": {Name: "LeftArrowBar", CodePoints: []int{8676}, Characters: []byte{0xe2, 0x87, 0xa4}}, + "LeftArrowRightArrow": {Name: "LeftArrowRightArrow", CodePoints: []int{8646}, Characters: []byte{0xe2, 0x87, 0x86}}, + "LeftCeiling": {Name: "LeftCeiling", CodePoints: []int{8968}, Characters: []byte{0xe2, 0x8c, 0x88}}, + "LeftDoubleBracket": {Name: "LeftDoubleBracket", CodePoints: []int{10214}, Characters: []byte{0xe2, 0x9f, 0xa6}}, + "LeftDownTeeVector": {Name: "LeftDownTeeVector", CodePoints: []int{10593}, Characters: []byte{0xe2, 0xa5, 0xa1}}, + "LeftDownVector": {Name: "LeftDownVector", CodePoints: []int{8643}, Characters: []byte{0xe2, 0x87, 0x83}}, + "LeftDownVectorBar": {Name: "LeftDownVectorBar", CodePoints: []int{10585}, Characters: []byte{0xe2, 0xa5, 0x99}}, + "LeftFloor": {Name: "LeftFloor", CodePoints: []int{8970}, Characters: []byte{0xe2, 0x8c, 0x8a}}, + "LeftRightArrow": {Name: "LeftRightArrow", CodePoints: []int{8596}, Characters: []byte{0xe2, 0x86, 0x94}}, + "LeftRightVector": {Name: "LeftRightVector", CodePoints: []int{10574}, Characters: []byte{0xe2, 0xa5, 0x8e}}, + "LeftTee": {Name: "LeftTee", CodePoints: []int{8867}, Characters: []byte{0xe2, 0x8a, 0xa3}}, + "LeftTeeArrow": {Name: "LeftTeeArrow", CodePoints: []int{8612}, Characters: []byte{0xe2, 0x86, 0xa4}}, + "LeftTeeVector": {Name: "LeftTeeVector", CodePoints: []int{10586}, Characters: []byte{0xe2, 0xa5, 0x9a}}, + "LeftTriangle": {Name: "LeftTriangle", CodePoints: []int{8882}, Characters: []byte{0xe2, 0x8a, 0xb2}}, + "LeftTriangleBar": {Name: "LeftTriangleBar", CodePoints: []int{10703}, Characters: []byte{0xe2, 0xa7, 0x8f}}, + "LeftTriangleEqual": {Name: "LeftTriangleEqual", CodePoints: []int{8884}, Characters: []byte{0xe2, 0x8a, 0xb4}}, + "LeftUpDownVector": {Name: "LeftUpDownVector", CodePoints: []int{10577}, Characters: []byte{0xe2, 0xa5, 0x91}}, + "LeftUpTeeVector": {Name: "LeftUpTeeVector", CodePoints: []int{10592}, Characters: []byte{0xe2, 0xa5, 0xa0}}, + "LeftUpVector": {Name: "LeftUpVector", CodePoints: []int{8639}, Characters: []byte{0xe2, 0x86, 0xbf}}, + "LeftUpVectorBar": {Name: "LeftUpVectorBar", CodePoints: []int{10584}, Characters: []byte{0xe2, 0xa5, 0x98}}, + "LeftVector": {Name: "LeftVector", CodePoints: []int{8636}, Characters: []byte{0xe2, 0x86, 0xbc}}, + "LeftVectorBar": {Name: "LeftVectorBar", CodePoints: []int{10578}, Characters: []byte{0xe2, 0xa5, 0x92}}, + "Leftarrow": {Name: "Leftarrow", CodePoints: []int{8656}, Characters: []byte{0xe2, 0x87, 0x90}}, + "Leftrightarrow": {Name: "Leftrightarrow", CodePoints: []int{8660}, Characters: []byte{0xe2, 0x87, 0x94}}, + "LessEqualGreater": {Name: "LessEqualGreater", CodePoints: []int{8922}, Characters: []byte{0xe2, 0x8b, 0x9a}}, + "LessFullEqual": {Name: "LessFullEqual", CodePoints: []int{8806}, Characters: []byte{0xe2, 0x89, 0xa6}}, + "LessGreater": {Name: "LessGreater", CodePoints: []int{8822}, Characters: []byte{0xe2, 0x89, 0xb6}}, + "LessLess": {Name: "LessLess", CodePoints: []int{10913}, Characters: []byte{0xe2, 0xaa, 0xa1}}, + "LessSlantEqual": {Name: "LessSlantEqual", CodePoints: []int{10877}, Characters: []byte{0xe2, 0xa9, 0xbd}}, + "LessTilde": {Name: "LessTilde", CodePoints: []int{8818}, Characters: []byte{0xe2, 0x89, 0xb2}}, + "Lfr": {Name: "Lfr", CodePoints: []int{120079}, Characters: []byte{0xf0, 0x9d, 0x94, 0x8f}}, + "Ll": {Name: "Ll", CodePoints: []int{8920}, Characters: []byte{0xe2, 0x8b, 0x98}}, + "Lleftarrow": {Name: "Lleftarrow", CodePoints: []int{8666}, Characters: []byte{0xe2, 0x87, 0x9a}}, + "Lmidot": {Name: "Lmidot", CodePoints: []int{319}, Characters: []byte{0xc4, 0xbf}}, + "LongLeftArrow": {Name: "LongLeftArrow", CodePoints: []int{10229}, Characters: []byte{0xe2, 0x9f, 0xb5}}, + "LongLeftRightArrow": {Name: "LongLeftRightArrow", CodePoints: []int{10231}, Characters: []byte{0xe2, 0x9f, 0xb7}}, + "LongRightArrow": {Name: "LongRightArrow", CodePoints: []int{10230}, Characters: []byte{0xe2, 0x9f, 0xb6}}, + "Longleftarrow": {Name: "Longleftarrow", CodePoints: []int{10232}, Characters: []byte{0xe2, 0x9f, 0xb8}}, + "Longleftrightarrow": {Name: "Longleftrightarrow", CodePoints: []int{10234}, Characters: []byte{0xe2, 0x9f, 0xba}}, + "Longrightarrow": {Name: "Longrightarrow", CodePoints: []int{10233}, Characters: []byte{0xe2, 0x9f, 0xb9}}, + "Lopf": {Name: "Lopf", CodePoints: []int{120131}, Characters: []byte{0xf0, 0x9d, 0x95, 0x83}}, + "LowerLeftArrow": {Name: "LowerLeftArrow", CodePoints: []int{8601}, Characters: []byte{0xe2, 0x86, 0x99}}, + "LowerRightArrow": {Name: "LowerRightArrow", CodePoints: []int{8600}, Characters: []byte{0xe2, 0x86, 0x98}}, + "Lscr": {Name: "Lscr", CodePoints: []int{8466}, Characters: []byte{0xe2, 0x84, 0x92}}, + "Lsh": {Name: "Lsh", CodePoints: []int{8624}, Characters: []byte{0xe2, 0x86, 0xb0}}, + "Lstrok": {Name: "Lstrok", CodePoints: []int{321}, Characters: []byte{0xc5, 0x81}}, + "Lt": {Name: "Lt", CodePoints: []int{8810}, Characters: []byte{0xe2, 0x89, 0xaa}}, + "Map": {Name: "Map", CodePoints: []int{10501}, Characters: []byte{0xe2, 0xa4, 0x85}}, + "Mcy": {Name: "Mcy", CodePoints: []int{1052}, Characters: []byte{0xd0, 0x9c}}, + "MediumSpace": {Name: "MediumSpace", CodePoints: []int{8287}, Characters: []byte{0xe2, 0x81, 0x9f}}, + "Mellintrf": {Name: "Mellintrf", CodePoints: []int{8499}, Characters: []byte{0xe2, 0x84, 0xb3}}, + "Mfr": {Name: "Mfr", CodePoints: []int{120080}, Characters: []byte{0xf0, 0x9d, 0x94, 0x90}}, + "MinusPlus": {Name: "MinusPlus", CodePoints: []int{8723}, Characters: []byte{0xe2, 0x88, 0x93}}, + "Mopf": {Name: "Mopf", CodePoints: []int{120132}, Characters: []byte{0xf0, 0x9d, 0x95, 0x84}}, + "Mscr": {Name: "Mscr", CodePoints: []int{8499}, Characters: []byte{0xe2, 0x84, 0xb3}}, + "Mu": {Name: "Mu", CodePoints: []int{924}, Characters: []byte{0xce, 0x9c}}, + "NJcy": {Name: "NJcy", CodePoints: []int{1034}, Characters: []byte{0xd0, 0x8a}}, + "Nacute": {Name: "Nacute", CodePoints: []int{323}, Characters: []byte{0xc5, 0x83}}, + "Ncaron": {Name: "Ncaron", CodePoints: []int{327}, Characters: []byte{0xc5, 0x87}}, + "Ncedil": {Name: "Ncedil", CodePoints: []int{325}, Characters: []byte{0xc5, 0x85}}, + "Ncy": {Name: "Ncy", CodePoints: []int{1053}, Characters: []byte{0xd0, 0x9d}}, + "NegativeMediumSpace": {Name: "NegativeMediumSpace", CodePoints: []int{8203}, Characters: []byte{0xe2, 0x80, 0x8b}}, + "NegativeThickSpace": {Name: "NegativeThickSpace", CodePoints: []int{8203}, Characters: []byte{0xe2, 0x80, 0x8b}}, + "NegativeThinSpace": {Name: "NegativeThinSpace", CodePoints: []int{8203}, Characters: []byte{0xe2, 0x80, 0x8b}}, + "NegativeVeryThinSpace": {Name: "NegativeVeryThinSpace", CodePoints: []int{8203}, Characters: []byte{0xe2, 0x80, 0x8b}}, + "NestedGreaterGreater": {Name: "NestedGreaterGreater", CodePoints: []int{8811}, Characters: []byte{0xe2, 0x89, 0xab}}, + "NestedLessLess": {Name: "NestedLessLess", CodePoints: []int{8810}, Characters: []byte{0xe2, 0x89, 0xaa}}, + "NewLine": {Name: "NewLine", CodePoints: []int{10}, Characters: []byte{0xa}}, + "Nfr": {Name: "Nfr", CodePoints: []int{120081}, Characters: []byte{0xf0, 0x9d, 0x94, 0x91}}, + "NoBreak": {Name: "NoBreak", CodePoints: []int{8288}, Characters: []byte{0xe2, 0x81, 0xa0}}, + "NonBreakingSpace": {Name: "NonBreakingSpace", CodePoints: []int{160}, Characters: []byte{0xc2, 0xa0}}, + "Nopf": {Name: "Nopf", CodePoints: []int{8469}, Characters: []byte{0xe2, 0x84, 0x95}}, + "Not": {Name: "Not", CodePoints: []int{10988}, Characters: []byte{0xe2, 0xab, 0xac}}, + "NotCongruent": {Name: "NotCongruent", CodePoints: []int{8802}, Characters: []byte{0xe2, 0x89, 0xa2}}, + "NotCupCap": {Name: "NotCupCap", CodePoints: []int{8813}, Characters: []byte{0xe2, 0x89, 0xad}}, + "NotDoubleVerticalBar": {Name: "NotDoubleVerticalBar", CodePoints: []int{8742}, Characters: []byte{0xe2, 0x88, 0xa6}}, + "NotElement": {Name: "NotElement", CodePoints: []int{8713}, Characters: []byte{0xe2, 0x88, 0x89}}, + "NotEqual": {Name: "NotEqual", CodePoints: []int{8800}, Characters: []byte{0xe2, 0x89, 0xa0}}, + "NotEqualTilde": {Name: "NotEqualTilde", CodePoints: []int{8770, 824}, Characters: []byte{0xe2, 0x89, 0x82, 0xcc, 0xb8}}, + "NotExists": {Name: "NotExists", CodePoints: []int{8708}, Characters: []byte{0xe2, 0x88, 0x84}}, + "NotGreater": {Name: "NotGreater", CodePoints: []int{8815}, Characters: []byte{0xe2, 0x89, 0xaf}}, + "NotGreaterEqual": {Name: "NotGreaterEqual", CodePoints: []int{8817}, Characters: []byte{0xe2, 0x89, 0xb1}}, + "NotGreaterFullEqual": {Name: "NotGreaterFullEqual", CodePoints: []int{8807, 824}, Characters: []byte{0xe2, 0x89, 0xa7, 0xcc, 0xb8}}, + "NotGreaterGreater": {Name: "NotGreaterGreater", CodePoints: []int{8811, 824}, Characters: []byte{0xe2, 0x89, 0xab, 0xcc, 0xb8}}, + "NotGreaterLess": {Name: "NotGreaterLess", CodePoints: []int{8825}, Characters: []byte{0xe2, 0x89, 0xb9}}, + "NotGreaterSlantEqual": {Name: "NotGreaterSlantEqual", CodePoints: []int{10878, 824}, Characters: []byte{0xe2, 0xa9, 0xbe, 0xcc, 0xb8}}, + "NotGreaterTilde": {Name: "NotGreaterTilde", CodePoints: []int{8821}, Characters: []byte{0xe2, 0x89, 0xb5}}, + "NotHumpDownHump": {Name: "NotHumpDownHump", CodePoints: []int{8782, 824}, Characters: []byte{0xe2, 0x89, 0x8e, 0xcc, 0xb8}}, + "NotHumpEqual": {Name: "NotHumpEqual", CodePoints: []int{8783, 824}, Characters: []byte{0xe2, 0x89, 0x8f, 0xcc, 0xb8}}, + "NotLeftTriangle": {Name: "NotLeftTriangle", CodePoints: []int{8938}, Characters: []byte{0xe2, 0x8b, 0xaa}}, + "NotLeftTriangleBar": {Name: "NotLeftTriangleBar", CodePoints: []int{10703, 824}, Characters: []byte{0xe2, 0xa7, 0x8f, 0xcc, 0xb8}}, + "NotLeftTriangleEqual": {Name: "NotLeftTriangleEqual", CodePoints: []int{8940}, Characters: []byte{0xe2, 0x8b, 0xac}}, + "NotLess": {Name: "NotLess", CodePoints: []int{8814}, Characters: []byte{0xe2, 0x89, 0xae}}, + "NotLessEqual": {Name: "NotLessEqual", CodePoints: []int{8816}, Characters: []byte{0xe2, 0x89, 0xb0}}, + "NotLessGreater": {Name: "NotLessGreater", CodePoints: []int{8824}, Characters: []byte{0xe2, 0x89, 0xb8}}, + "NotLessLess": {Name: "NotLessLess", CodePoints: []int{8810, 824}, Characters: []byte{0xe2, 0x89, 0xaa, 0xcc, 0xb8}}, + "NotLessSlantEqual": {Name: "NotLessSlantEqual", CodePoints: []int{10877, 824}, Characters: []byte{0xe2, 0xa9, 0xbd, 0xcc, 0xb8}}, + "NotLessTilde": {Name: "NotLessTilde", CodePoints: []int{8820}, Characters: []byte{0xe2, 0x89, 0xb4}}, + "NotNestedGreaterGreater": {Name: "NotNestedGreaterGreater", CodePoints: []int{10914, 824}, Characters: []byte{0xe2, 0xaa, 0xa2, 0xcc, 0xb8}}, + "NotNestedLessLess": {Name: "NotNestedLessLess", CodePoints: []int{10913, 824}, Characters: []byte{0xe2, 0xaa, 0xa1, 0xcc, 0xb8}}, + "NotPrecedes": {Name: "NotPrecedes", CodePoints: []int{8832}, Characters: []byte{0xe2, 0x8a, 0x80}}, + "NotPrecedesEqual": {Name: "NotPrecedesEqual", CodePoints: []int{10927, 824}, Characters: []byte{0xe2, 0xaa, 0xaf, 0xcc, 0xb8}}, + "NotPrecedesSlantEqual": {Name: "NotPrecedesSlantEqual", CodePoints: []int{8928}, Characters: []byte{0xe2, 0x8b, 0xa0}}, + "NotReverseElement": {Name: "NotReverseElement", CodePoints: []int{8716}, Characters: []byte{0xe2, 0x88, 0x8c}}, + "NotRightTriangle": {Name: "NotRightTriangle", CodePoints: []int{8939}, Characters: []byte{0xe2, 0x8b, 0xab}}, + "NotRightTriangleBar": {Name: "NotRightTriangleBar", CodePoints: []int{10704, 824}, Characters: []byte{0xe2, 0xa7, 0x90, 0xcc, 0xb8}}, + "NotRightTriangleEqual": {Name: "NotRightTriangleEqual", CodePoints: []int{8941}, Characters: []byte{0xe2, 0x8b, 0xad}}, + "NotSquareSubset": {Name: "NotSquareSubset", CodePoints: []int{8847, 824}, Characters: []byte{0xe2, 0x8a, 0x8f, 0xcc, 0xb8}}, + "NotSquareSubsetEqual": {Name: "NotSquareSubsetEqual", CodePoints: []int{8930}, Characters: []byte{0xe2, 0x8b, 0xa2}}, + "NotSquareSuperset": {Name: "NotSquareSuperset", CodePoints: []int{8848, 824}, Characters: []byte{0xe2, 0x8a, 0x90, 0xcc, 0xb8}}, + "NotSquareSupersetEqual": {Name: "NotSquareSupersetEqual", CodePoints: []int{8931}, Characters: []byte{0xe2, 0x8b, 0xa3}}, + "NotSubset": {Name: "NotSubset", CodePoints: []int{8834, 8402}, Characters: []byte{0xe2, 0x8a, 0x82, 0xe2, 0x83, 0x92}}, + "NotSubsetEqual": {Name: "NotSubsetEqual", CodePoints: []int{8840}, Characters: []byte{0xe2, 0x8a, 0x88}}, + "NotSucceeds": {Name: "NotSucceeds", CodePoints: []int{8833}, Characters: []byte{0xe2, 0x8a, 0x81}}, + "NotSucceedsEqual": {Name: "NotSucceedsEqual", CodePoints: []int{10928, 824}, Characters: []byte{0xe2, 0xaa, 0xb0, 0xcc, 0xb8}}, + "NotSucceedsSlantEqual": {Name: "NotSucceedsSlantEqual", CodePoints: []int{8929}, Characters: []byte{0xe2, 0x8b, 0xa1}}, + "NotSucceedsTilde": {Name: "NotSucceedsTilde", CodePoints: []int{8831, 824}, Characters: []byte{0xe2, 0x89, 0xbf, 0xcc, 0xb8}}, + "NotSuperset": {Name: "NotSuperset", CodePoints: []int{8835, 8402}, Characters: []byte{0xe2, 0x8a, 0x83, 0xe2, 0x83, 0x92}}, + "NotSupersetEqual": {Name: "NotSupersetEqual", CodePoints: []int{8841}, Characters: []byte{0xe2, 0x8a, 0x89}}, + "NotTilde": {Name: "NotTilde", CodePoints: []int{8769}, Characters: []byte{0xe2, 0x89, 0x81}}, + "NotTildeEqual": {Name: "NotTildeEqual", CodePoints: []int{8772}, Characters: []byte{0xe2, 0x89, 0x84}}, + "NotTildeFullEqual": {Name: "NotTildeFullEqual", CodePoints: []int{8775}, Characters: []byte{0xe2, 0x89, 0x87}}, + "NotTildeTilde": {Name: "NotTildeTilde", CodePoints: []int{8777}, Characters: []byte{0xe2, 0x89, 0x89}}, + "NotVerticalBar": {Name: "NotVerticalBar", CodePoints: []int{8740}, Characters: []byte{0xe2, 0x88, 0xa4}}, + "Nscr": {Name: "Nscr", CodePoints: []int{119977}, Characters: []byte{0xf0, 0x9d, 0x92, 0xa9}}, + "Ntilde": {Name: "Ntilde", CodePoints: []int{209}, Characters: []byte{0xc3, 0x91}}, + "Nu": {Name: "Nu", CodePoints: []int{925}, Characters: []byte{0xce, 0x9d}}, + "OElig": {Name: "OElig", CodePoints: []int{338}, Characters: []byte{0xc5, 0x92}}, + "Oacute": {Name: "Oacute", CodePoints: []int{211}, Characters: []byte{0xc3, 0x93}}, + "Ocirc": {Name: "Ocirc", CodePoints: []int{212}, Characters: []byte{0xc3, 0x94}}, + "Ocy": {Name: "Ocy", CodePoints: []int{1054}, Characters: []byte{0xd0, 0x9e}}, + "Odblac": {Name: "Odblac", CodePoints: []int{336}, Characters: []byte{0xc5, 0x90}}, + "Ofr": {Name: "Ofr", CodePoints: []int{120082}, Characters: []byte{0xf0, 0x9d, 0x94, 0x92}}, + "Ograve": {Name: "Ograve", CodePoints: []int{210}, Characters: []byte{0xc3, 0x92}}, + "Omacr": {Name: "Omacr", CodePoints: []int{332}, Characters: []byte{0xc5, 0x8c}}, + "Omega": {Name: "Omega", CodePoints: []int{937}, Characters: []byte{0xce, 0xa9}}, + "Omicron": {Name: "Omicron", CodePoints: []int{927}, Characters: []byte{0xce, 0x9f}}, + "Oopf": {Name: "Oopf", CodePoints: []int{120134}, Characters: []byte{0xf0, 0x9d, 0x95, 0x86}}, + "OpenCurlyDoubleQuote": {Name: "OpenCurlyDoubleQuote", CodePoints: []int{8220}, Characters: []byte{0xe2, 0x80, 0x9c}}, + "OpenCurlyQuote": {Name: "OpenCurlyQuote", CodePoints: []int{8216}, Characters: []byte{0xe2, 0x80, 0x98}}, + "Or": {Name: "Or", CodePoints: []int{10836}, Characters: []byte{0xe2, 0xa9, 0x94}}, + "Oscr": {Name: "Oscr", CodePoints: []int{119978}, Characters: []byte{0xf0, 0x9d, 0x92, 0xaa}}, + "Oslash": {Name: "Oslash", CodePoints: []int{216}, Characters: []byte{0xc3, 0x98}}, + "Otilde": {Name: "Otilde", CodePoints: []int{213}, Characters: []byte{0xc3, 0x95}}, + "Otimes": {Name: "Otimes", CodePoints: []int{10807}, Characters: []byte{0xe2, 0xa8, 0xb7}}, + "Ouml": {Name: "Ouml", CodePoints: []int{214}, Characters: []byte{0xc3, 0x96}}, + "OverBar": {Name: "OverBar", CodePoints: []int{8254}, Characters: []byte{0xe2, 0x80, 0xbe}}, + "OverBrace": {Name: "OverBrace", CodePoints: []int{9182}, Characters: []byte{0xe2, 0x8f, 0x9e}}, + "OverBracket": {Name: "OverBracket", CodePoints: []int{9140}, Characters: []byte{0xe2, 0x8e, 0xb4}}, + "OverParenthesis": {Name: "OverParenthesis", CodePoints: []int{9180}, Characters: []byte{0xe2, 0x8f, 0x9c}}, + "PartialD": {Name: "PartialD", CodePoints: []int{8706}, Characters: []byte{0xe2, 0x88, 0x82}}, + "Pcy": {Name: "Pcy", CodePoints: []int{1055}, Characters: []byte{0xd0, 0x9f}}, + "Pfr": {Name: "Pfr", CodePoints: []int{120083}, Characters: []byte{0xf0, 0x9d, 0x94, 0x93}}, + "Phi": {Name: "Phi", CodePoints: []int{934}, Characters: []byte{0xce, 0xa6}}, + "Pi": {Name: "Pi", CodePoints: []int{928}, Characters: []byte{0xce, 0xa0}}, + "PlusMinus": {Name: "PlusMinus", CodePoints: []int{177}, Characters: []byte{0xc2, 0xb1}}, + "Poincareplane": {Name: "Poincareplane", CodePoints: []int{8460}, Characters: []byte{0xe2, 0x84, 0x8c}}, + "Popf": {Name: "Popf", CodePoints: []int{8473}, Characters: []byte{0xe2, 0x84, 0x99}}, + "Pr": {Name: "Pr", CodePoints: []int{10939}, Characters: []byte{0xe2, 0xaa, 0xbb}}, + "Precedes": {Name: "Precedes", CodePoints: []int{8826}, Characters: []byte{0xe2, 0x89, 0xba}}, + "PrecedesEqual": {Name: "PrecedesEqual", CodePoints: []int{10927}, Characters: []byte{0xe2, 0xaa, 0xaf}}, + "PrecedesSlantEqual": {Name: "PrecedesSlantEqual", CodePoints: []int{8828}, Characters: []byte{0xe2, 0x89, 0xbc}}, + "PrecedesTilde": {Name: "PrecedesTilde", CodePoints: []int{8830}, Characters: []byte{0xe2, 0x89, 0xbe}}, + "Prime": {Name: "Prime", CodePoints: []int{8243}, Characters: []byte{0xe2, 0x80, 0xb3}}, + "Product": {Name: "Product", CodePoints: []int{8719}, Characters: []byte{0xe2, 0x88, 0x8f}}, + "Proportion": {Name: "Proportion", CodePoints: []int{8759}, Characters: []byte{0xe2, 0x88, 0xb7}}, + "Proportional": {Name: "Proportional", CodePoints: []int{8733}, Characters: []byte{0xe2, 0x88, 0x9d}}, + "Pscr": {Name: "Pscr", CodePoints: []int{119979}, Characters: []byte{0xf0, 0x9d, 0x92, 0xab}}, + "Psi": {Name: "Psi", CodePoints: []int{936}, Characters: []byte{0xce, 0xa8}}, + "QUOT": {Name: "QUOT", CodePoints: []int{34}, Characters: []byte{0x22}}, + "Qfr": {Name: "Qfr", CodePoints: []int{120084}, Characters: []byte{0xf0, 0x9d, 0x94, 0x94}}, + "Qopf": {Name: "Qopf", CodePoints: []int{8474}, Characters: []byte{0xe2, 0x84, 0x9a}}, + "Qscr": {Name: "Qscr", CodePoints: []int{119980}, Characters: []byte{0xf0, 0x9d, 0x92, 0xac}}, + "RBarr": {Name: "RBarr", CodePoints: []int{10512}, Characters: []byte{0xe2, 0xa4, 0x90}}, + "REG": {Name: "REG", CodePoints: []int{174}, Characters: []byte{0xc2, 0xae}}, + "Racute": {Name: "Racute", CodePoints: []int{340}, Characters: []byte{0xc5, 0x94}}, + "Rang": {Name: "Rang", CodePoints: []int{10219}, Characters: []byte{0xe2, 0x9f, 0xab}}, + "Rarr": {Name: "Rarr", CodePoints: []int{8608}, Characters: []byte{0xe2, 0x86, 0xa0}}, + "Rarrtl": {Name: "Rarrtl", CodePoints: []int{10518}, Characters: []byte{0xe2, 0xa4, 0x96}}, + "Rcaron": {Name: "Rcaron", CodePoints: []int{344}, Characters: []byte{0xc5, 0x98}}, + "Rcedil": {Name: "Rcedil", CodePoints: []int{342}, Characters: []byte{0xc5, 0x96}}, + "Rcy": {Name: "Rcy", CodePoints: []int{1056}, Characters: []byte{0xd0, 0xa0}}, + "Re": {Name: "Re", CodePoints: []int{8476}, Characters: []byte{0xe2, 0x84, 0x9c}}, + "ReverseElement": {Name: "ReverseElement", CodePoints: []int{8715}, Characters: []byte{0xe2, 0x88, 0x8b}}, + "ReverseEquilibrium": {Name: "ReverseEquilibrium", CodePoints: []int{8651}, Characters: []byte{0xe2, 0x87, 0x8b}}, + "ReverseUpEquilibrium": {Name: "ReverseUpEquilibrium", CodePoints: []int{10607}, Characters: []byte{0xe2, 0xa5, 0xaf}}, + "Rfr": {Name: "Rfr", CodePoints: []int{8476}, Characters: []byte{0xe2, 0x84, 0x9c}}, + "Rho": {Name: "Rho", CodePoints: []int{929}, Characters: []byte{0xce, 0xa1}}, + "RightAngleBracket": {Name: "RightAngleBracket", CodePoints: []int{10217}, Characters: []byte{0xe2, 0x9f, 0xa9}}, + "RightArrow": {Name: "RightArrow", CodePoints: []int{8594}, Characters: []byte{0xe2, 0x86, 0x92}}, + "RightArrowBar": {Name: "RightArrowBar", CodePoints: []int{8677}, Characters: []byte{0xe2, 0x87, 0xa5}}, + "RightArrowLeftArrow": {Name: "RightArrowLeftArrow", CodePoints: []int{8644}, Characters: []byte{0xe2, 0x87, 0x84}}, + "RightCeiling": {Name: "RightCeiling", CodePoints: []int{8969}, Characters: []byte{0xe2, 0x8c, 0x89}}, + "RightDoubleBracket": {Name: "RightDoubleBracket", CodePoints: []int{10215}, Characters: []byte{0xe2, 0x9f, 0xa7}}, + "RightDownTeeVector": {Name: "RightDownTeeVector", CodePoints: []int{10589}, Characters: []byte{0xe2, 0xa5, 0x9d}}, + "RightDownVector": {Name: "RightDownVector", CodePoints: []int{8642}, Characters: []byte{0xe2, 0x87, 0x82}}, + "RightDownVectorBar": {Name: "RightDownVectorBar", CodePoints: []int{10581}, Characters: []byte{0xe2, 0xa5, 0x95}}, + "RightFloor": {Name: "RightFloor", CodePoints: []int{8971}, Characters: []byte{0xe2, 0x8c, 0x8b}}, + "RightTee": {Name: "RightTee", CodePoints: []int{8866}, Characters: []byte{0xe2, 0x8a, 0xa2}}, + "RightTeeArrow": {Name: "RightTeeArrow", CodePoints: []int{8614}, Characters: []byte{0xe2, 0x86, 0xa6}}, + "RightTeeVector": {Name: "RightTeeVector", CodePoints: []int{10587}, Characters: []byte{0xe2, 0xa5, 0x9b}}, + "RightTriangle": {Name: "RightTriangle", CodePoints: []int{8883}, Characters: []byte{0xe2, 0x8a, 0xb3}}, + "RightTriangleBar": {Name: "RightTriangleBar", CodePoints: []int{10704}, Characters: []byte{0xe2, 0xa7, 0x90}}, + "RightTriangleEqual": {Name: "RightTriangleEqual", CodePoints: []int{8885}, Characters: []byte{0xe2, 0x8a, 0xb5}}, + "RightUpDownVector": {Name: "RightUpDownVector", CodePoints: []int{10575}, Characters: []byte{0xe2, 0xa5, 0x8f}}, + "RightUpTeeVector": {Name: "RightUpTeeVector", CodePoints: []int{10588}, Characters: []byte{0xe2, 0xa5, 0x9c}}, + "RightUpVector": {Name: "RightUpVector", CodePoints: []int{8638}, Characters: []byte{0xe2, 0x86, 0xbe}}, + "RightUpVectorBar": {Name: "RightUpVectorBar", CodePoints: []int{10580}, Characters: []byte{0xe2, 0xa5, 0x94}}, + "RightVector": {Name: "RightVector", CodePoints: []int{8640}, Characters: []byte{0xe2, 0x87, 0x80}}, + "RightVectorBar": {Name: "RightVectorBar", CodePoints: []int{10579}, Characters: []byte{0xe2, 0xa5, 0x93}}, + "Rightarrow": {Name: "Rightarrow", CodePoints: []int{8658}, Characters: []byte{0xe2, 0x87, 0x92}}, + "Ropf": {Name: "Ropf", CodePoints: []int{8477}, Characters: []byte{0xe2, 0x84, 0x9d}}, + "RoundImplies": {Name: "RoundImplies", CodePoints: []int{10608}, Characters: []byte{0xe2, 0xa5, 0xb0}}, + "Rrightarrow": {Name: "Rrightarrow", CodePoints: []int{8667}, Characters: []byte{0xe2, 0x87, 0x9b}}, + "Rscr": {Name: "Rscr", CodePoints: []int{8475}, Characters: []byte{0xe2, 0x84, 0x9b}}, + "Rsh": {Name: "Rsh", CodePoints: []int{8625}, Characters: []byte{0xe2, 0x86, 0xb1}}, + "RuleDelayed": {Name: "RuleDelayed", CodePoints: []int{10740}, Characters: []byte{0xe2, 0xa7, 0xb4}}, + "SHCHcy": {Name: "SHCHcy", CodePoints: []int{1065}, Characters: []byte{0xd0, 0xa9}}, + "SHcy": {Name: "SHcy", CodePoints: []int{1064}, Characters: []byte{0xd0, 0xa8}}, + "SOFTcy": {Name: "SOFTcy", CodePoints: []int{1068}, Characters: []byte{0xd0, 0xac}}, + "Sacute": {Name: "Sacute", CodePoints: []int{346}, Characters: []byte{0xc5, 0x9a}}, + "Sc": {Name: "Sc", CodePoints: []int{10940}, Characters: []byte{0xe2, 0xaa, 0xbc}}, + "Scaron": {Name: "Scaron", CodePoints: []int{352}, Characters: []byte{0xc5, 0xa0}}, + "Scedil": {Name: "Scedil", CodePoints: []int{350}, Characters: []byte{0xc5, 0x9e}}, + "Scirc": {Name: "Scirc", CodePoints: []int{348}, Characters: []byte{0xc5, 0x9c}}, + "Scy": {Name: "Scy", CodePoints: []int{1057}, Characters: []byte{0xd0, 0xa1}}, + "Sfr": {Name: "Sfr", CodePoints: []int{120086}, Characters: []byte{0xf0, 0x9d, 0x94, 0x96}}, + "ShortDownArrow": {Name: "ShortDownArrow", CodePoints: []int{8595}, Characters: []byte{0xe2, 0x86, 0x93}}, + "ShortLeftArrow": {Name: "ShortLeftArrow", CodePoints: []int{8592}, Characters: []byte{0xe2, 0x86, 0x90}}, + "ShortRightArrow": {Name: "ShortRightArrow", CodePoints: []int{8594}, Characters: []byte{0xe2, 0x86, 0x92}}, + "ShortUpArrow": {Name: "ShortUpArrow", CodePoints: []int{8593}, Characters: []byte{0xe2, 0x86, 0x91}}, + "Sigma": {Name: "Sigma", CodePoints: []int{931}, Characters: []byte{0xce, 0xa3}}, + "SmallCircle": {Name: "SmallCircle", CodePoints: []int{8728}, Characters: []byte{0xe2, 0x88, 0x98}}, + "Sopf": {Name: "Sopf", CodePoints: []int{120138}, Characters: []byte{0xf0, 0x9d, 0x95, 0x8a}}, + "Sqrt": {Name: "Sqrt", CodePoints: []int{8730}, Characters: []byte{0xe2, 0x88, 0x9a}}, + "Square": {Name: "Square", CodePoints: []int{9633}, Characters: []byte{0xe2, 0x96, 0xa1}}, + "SquareIntersection": {Name: "SquareIntersection", CodePoints: []int{8851}, Characters: []byte{0xe2, 0x8a, 0x93}}, + "SquareSubset": {Name: "SquareSubset", CodePoints: []int{8847}, Characters: []byte{0xe2, 0x8a, 0x8f}}, + "SquareSubsetEqual": {Name: "SquareSubsetEqual", CodePoints: []int{8849}, Characters: []byte{0xe2, 0x8a, 0x91}}, + "SquareSuperset": {Name: "SquareSuperset", CodePoints: []int{8848}, Characters: []byte{0xe2, 0x8a, 0x90}}, + "SquareSupersetEqual": {Name: "SquareSupersetEqual", CodePoints: []int{8850}, Characters: []byte{0xe2, 0x8a, 0x92}}, + "SquareUnion": {Name: "SquareUnion", CodePoints: []int{8852}, Characters: []byte{0xe2, 0x8a, 0x94}}, + "Sscr": {Name: "Sscr", CodePoints: []int{119982}, Characters: []byte{0xf0, 0x9d, 0x92, 0xae}}, + "Star": {Name: "Star", CodePoints: []int{8902}, Characters: []byte{0xe2, 0x8b, 0x86}}, + "Sub": {Name: "Sub", CodePoints: []int{8912}, Characters: []byte{0xe2, 0x8b, 0x90}}, + "Subset": {Name: "Subset", CodePoints: []int{8912}, Characters: []byte{0xe2, 0x8b, 0x90}}, + "SubsetEqual": {Name: "SubsetEqual", CodePoints: []int{8838}, Characters: []byte{0xe2, 0x8a, 0x86}}, + "Succeeds": {Name: "Succeeds", CodePoints: []int{8827}, Characters: []byte{0xe2, 0x89, 0xbb}}, + "SucceedsEqual": {Name: "SucceedsEqual", CodePoints: []int{10928}, Characters: []byte{0xe2, 0xaa, 0xb0}}, + "SucceedsSlantEqual": {Name: "SucceedsSlantEqual", CodePoints: []int{8829}, Characters: []byte{0xe2, 0x89, 0xbd}}, + "SucceedsTilde": {Name: "SucceedsTilde", CodePoints: []int{8831}, Characters: []byte{0xe2, 0x89, 0xbf}}, + "SuchThat": {Name: "SuchThat", CodePoints: []int{8715}, Characters: []byte{0xe2, 0x88, 0x8b}}, + "Sum": {Name: "Sum", CodePoints: []int{8721}, Characters: []byte{0xe2, 0x88, 0x91}}, + "Sup": {Name: "Sup", CodePoints: []int{8913}, Characters: []byte{0xe2, 0x8b, 0x91}}, + "Superset": {Name: "Superset", CodePoints: []int{8835}, Characters: []byte{0xe2, 0x8a, 0x83}}, + "SupersetEqual": {Name: "SupersetEqual", CodePoints: []int{8839}, Characters: []byte{0xe2, 0x8a, 0x87}}, + "Supset": {Name: "Supset", CodePoints: []int{8913}, Characters: []byte{0xe2, 0x8b, 0x91}}, + "THORN": {Name: "THORN", CodePoints: []int{222}, Characters: []byte{0xc3, 0x9e}}, + "TRADE": {Name: "TRADE", CodePoints: []int{8482}, Characters: []byte{0xe2, 0x84, 0xa2}}, + "TSHcy": {Name: "TSHcy", CodePoints: []int{1035}, Characters: []byte{0xd0, 0x8b}}, + "TScy": {Name: "TScy", CodePoints: []int{1062}, Characters: []byte{0xd0, 0xa6}}, + "Tab": {Name: "Tab", CodePoints: []int{9}, Characters: []byte{0x9}}, + "Tau": {Name: "Tau", CodePoints: []int{932}, Characters: []byte{0xce, 0xa4}}, + "Tcaron": {Name: "Tcaron", CodePoints: []int{356}, Characters: []byte{0xc5, 0xa4}}, + "Tcedil": {Name: "Tcedil", CodePoints: []int{354}, Characters: []byte{0xc5, 0xa2}}, + "Tcy": {Name: "Tcy", CodePoints: []int{1058}, Characters: []byte{0xd0, 0xa2}}, + "Tfr": {Name: "Tfr", CodePoints: []int{120087}, Characters: []byte{0xf0, 0x9d, 0x94, 0x97}}, + "Therefore": {Name: "Therefore", CodePoints: []int{8756}, Characters: []byte{0xe2, 0x88, 0xb4}}, + "Theta": {Name: "Theta", CodePoints: []int{920}, Characters: []byte{0xce, 0x98}}, + "ThickSpace": {Name: "ThickSpace", CodePoints: []int{8287, 8202}, Characters: []byte{0xe2, 0x81, 0x9f, 0xe2, 0x80, 0x8a}}, + "ThinSpace": {Name: "ThinSpace", CodePoints: []int{8201}, Characters: []byte{0xe2, 0x80, 0x89}}, + "Tilde": {Name: "Tilde", CodePoints: []int{8764}, Characters: []byte{0xe2, 0x88, 0xbc}}, + "TildeEqual": {Name: "TildeEqual", CodePoints: []int{8771}, Characters: []byte{0xe2, 0x89, 0x83}}, + "TildeFullEqual": {Name: "TildeFullEqual", CodePoints: []int{8773}, Characters: []byte{0xe2, 0x89, 0x85}}, + "TildeTilde": {Name: "TildeTilde", CodePoints: []int{8776}, Characters: []byte{0xe2, 0x89, 0x88}}, + "Topf": {Name: "Topf", CodePoints: []int{120139}, Characters: []byte{0xf0, 0x9d, 0x95, 0x8b}}, + "TripleDot": {Name: "TripleDot", CodePoints: []int{8411}, Characters: []byte{0xe2, 0x83, 0x9b}}, + "Tscr": {Name: "Tscr", CodePoints: []int{119983}, Characters: []byte{0xf0, 0x9d, 0x92, 0xaf}}, + "Tstrok": {Name: "Tstrok", CodePoints: []int{358}, Characters: []byte{0xc5, 0xa6}}, + "Uacute": {Name: "Uacute", CodePoints: []int{218}, Characters: []byte{0xc3, 0x9a}}, + "Uarr": {Name: "Uarr", CodePoints: []int{8607}, Characters: []byte{0xe2, 0x86, 0x9f}}, + "Uarrocir": {Name: "Uarrocir", CodePoints: []int{10569}, Characters: []byte{0xe2, 0xa5, 0x89}}, + "Ubrcy": {Name: "Ubrcy", CodePoints: []int{1038}, Characters: []byte{0xd0, 0x8e}}, + "Ubreve": {Name: "Ubreve", CodePoints: []int{364}, Characters: []byte{0xc5, 0xac}}, + "Ucirc": {Name: "Ucirc", CodePoints: []int{219}, Characters: []byte{0xc3, 0x9b}}, + "Ucy": {Name: "Ucy", CodePoints: []int{1059}, Characters: []byte{0xd0, 0xa3}}, + "Udblac": {Name: "Udblac", CodePoints: []int{368}, Characters: []byte{0xc5, 0xb0}}, + "Ufr": {Name: "Ufr", CodePoints: []int{120088}, Characters: []byte{0xf0, 0x9d, 0x94, 0x98}}, + "Ugrave": {Name: "Ugrave", CodePoints: []int{217}, Characters: []byte{0xc3, 0x99}}, + "Umacr": {Name: "Umacr", CodePoints: []int{362}, Characters: []byte{0xc5, 0xaa}}, + "UnderBar": {Name: "UnderBar", CodePoints: []int{95}, Characters: []byte{0x5f}}, + "UnderBrace": {Name: "UnderBrace", CodePoints: []int{9183}, Characters: []byte{0xe2, 0x8f, 0x9f}}, + "UnderBracket": {Name: "UnderBracket", CodePoints: []int{9141}, Characters: []byte{0xe2, 0x8e, 0xb5}}, + "UnderParenthesis": {Name: "UnderParenthesis", CodePoints: []int{9181}, Characters: []byte{0xe2, 0x8f, 0x9d}}, + "Union": {Name: "Union", CodePoints: []int{8899}, Characters: []byte{0xe2, 0x8b, 0x83}}, + "UnionPlus": {Name: "UnionPlus", CodePoints: []int{8846}, Characters: []byte{0xe2, 0x8a, 0x8e}}, + "Uogon": {Name: "Uogon", CodePoints: []int{370}, Characters: []byte{0xc5, 0xb2}}, + "Uopf": {Name: "Uopf", CodePoints: []int{120140}, Characters: []byte{0xf0, 0x9d, 0x95, 0x8c}}, + "UpArrow": {Name: "UpArrow", CodePoints: []int{8593}, Characters: []byte{0xe2, 0x86, 0x91}}, + "UpArrowBar": {Name: "UpArrowBar", CodePoints: []int{10514}, Characters: []byte{0xe2, 0xa4, 0x92}}, + "UpArrowDownArrow": {Name: "UpArrowDownArrow", CodePoints: []int{8645}, Characters: []byte{0xe2, 0x87, 0x85}}, + "UpDownArrow": {Name: "UpDownArrow", CodePoints: []int{8597}, Characters: []byte{0xe2, 0x86, 0x95}}, + "UpEquilibrium": {Name: "UpEquilibrium", CodePoints: []int{10606}, Characters: []byte{0xe2, 0xa5, 0xae}}, + "UpTee": {Name: "UpTee", CodePoints: []int{8869}, Characters: []byte{0xe2, 0x8a, 0xa5}}, + "UpTeeArrow": {Name: "UpTeeArrow", CodePoints: []int{8613}, Characters: []byte{0xe2, 0x86, 0xa5}}, + "Uparrow": {Name: "Uparrow", CodePoints: []int{8657}, Characters: []byte{0xe2, 0x87, 0x91}}, + "Updownarrow": {Name: "Updownarrow", CodePoints: []int{8661}, Characters: []byte{0xe2, 0x87, 0x95}}, + "UpperLeftArrow": {Name: "UpperLeftArrow", CodePoints: []int{8598}, Characters: []byte{0xe2, 0x86, 0x96}}, + "UpperRightArrow": {Name: "UpperRightArrow", CodePoints: []int{8599}, Characters: []byte{0xe2, 0x86, 0x97}}, + "Upsi": {Name: "Upsi", CodePoints: []int{978}, Characters: []byte{0xcf, 0x92}}, + "Upsilon": {Name: "Upsilon", CodePoints: []int{933}, Characters: []byte{0xce, 0xa5}}, + "Uring": {Name: "Uring", CodePoints: []int{366}, Characters: []byte{0xc5, 0xae}}, + "Uscr": {Name: "Uscr", CodePoints: []int{119984}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb0}}, + "Utilde": {Name: "Utilde", CodePoints: []int{360}, Characters: []byte{0xc5, 0xa8}}, + "Uuml": {Name: "Uuml", CodePoints: []int{220}, Characters: []byte{0xc3, 0x9c}}, + "VDash": {Name: "VDash", CodePoints: []int{8875}, Characters: []byte{0xe2, 0x8a, 0xab}}, + "Vbar": {Name: "Vbar", CodePoints: []int{10987}, Characters: []byte{0xe2, 0xab, 0xab}}, + "Vcy": {Name: "Vcy", CodePoints: []int{1042}, Characters: []byte{0xd0, 0x92}}, + "Vdash": {Name: "Vdash", CodePoints: []int{8873}, Characters: []byte{0xe2, 0x8a, 0xa9}}, + "Vdashl": {Name: "Vdashl", CodePoints: []int{10982}, Characters: []byte{0xe2, 0xab, 0xa6}}, + "Vee": {Name: "Vee", CodePoints: []int{8897}, Characters: []byte{0xe2, 0x8b, 0x81}}, + "Verbar": {Name: "Verbar", CodePoints: []int{8214}, Characters: []byte{0xe2, 0x80, 0x96}}, + "Vert": {Name: "Vert", CodePoints: []int{8214}, Characters: []byte{0xe2, 0x80, 0x96}}, + "VerticalBar": {Name: "VerticalBar", CodePoints: []int{8739}, Characters: []byte{0xe2, 0x88, 0xa3}}, + "VerticalLine": {Name: "VerticalLine", CodePoints: []int{124}, Characters: []byte{0x7c}}, + "VerticalSeparator": {Name: "VerticalSeparator", CodePoints: []int{10072}, Characters: []byte{0xe2, 0x9d, 0x98}}, + "VerticalTilde": {Name: "VerticalTilde", CodePoints: []int{8768}, Characters: []byte{0xe2, 0x89, 0x80}}, + "VeryThinSpace": {Name: "VeryThinSpace", CodePoints: []int{8202}, Characters: []byte{0xe2, 0x80, 0x8a}}, + "Vfr": {Name: "Vfr", CodePoints: []int{120089}, Characters: []byte{0xf0, 0x9d, 0x94, 0x99}}, + "Vopf": {Name: "Vopf", CodePoints: []int{120141}, Characters: []byte{0xf0, 0x9d, 0x95, 0x8d}}, + "Vscr": {Name: "Vscr", CodePoints: []int{119985}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb1}}, + "Vvdash": {Name: "Vvdash", CodePoints: []int{8874}, Characters: []byte{0xe2, 0x8a, 0xaa}}, + "Wcirc": {Name: "Wcirc", CodePoints: []int{372}, Characters: []byte{0xc5, 0xb4}}, + "Wedge": {Name: "Wedge", CodePoints: []int{8896}, Characters: []byte{0xe2, 0x8b, 0x80}}, + "Wfr": {Name: "Wfr", CodePoints: []int{120090}, Characters: []byte{0xf0, 0x9d, 0x94, 0x9a}}, + "Wopf": {Name: "Wopf", CodePoints: []int{120142}, Characters: []byte{0xf0, 0x9d, 0x95, 0x8e}}, + "Wscr": {Name: "Wscr", CodePoints: []int{119986}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb2}}, + "Xfr": {Name: "Xfr", CodePoints: []int{120091}, Characters: []byte{0xf0, 0x9d, 0x94, 0x9b}}, + "Xi": {Name: "Xi", CodePoints: []int{926}, Characters: []byte{0xce, 0x9e}}, + "Xopf": {Name: "Xopf", CodePoints: []int{120143}, Characters: []byte{0xf0, 0x9d, 0x95, 0x8f}}, + "Xscr": {Name: "Xscr", CodePoints: []int{119987}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb3}}, + "YAcy": {Name: "YAcy", CodePoints: []int{1071}, Characters: []byte{0xd0, 0xaf}}, + "YIcy": {Name: "YIcy", CodePoints: []int{1031}, Characters: []byte{0xd0, 0x87}}, + "YUcy": {Name: "YUcy", CodePoints: []int{1070}, Characters: []byte{0xd0, 0xae}}, + "Yacute": {Name: "Yacute", CodePoints: []int{221}, Characters: []byte{0xc3, 0x9d}}, + "Ycirc": {Name: "Ycirc", CodePoints: []int{374}, Characters: []byte{0xc5, 0xb6}}, + "Ycy": {Name: "Ycy", CodePoints: []int{1067}, Characters: []byte{0xd0, 0xab}}, + "Yfr": {Name: "Yfr", CodePoints: []int{120092}, Characters: []byte{0xf0, 0x9d, 0x94, 0x9c}}, + "Yopf": {Name: "Yopf", CodePoints: []int{120144}, Characters: []byte{0xf0, 0x9d, 0x95, 0x90}}, + "Yscr": {Name: "Yscr", CodePoints: []int{119988}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb4}}, + "Yuml": {Name: "Yuml", CodePoints: []int{376}, Characters: []byte{0xc5, 0xb8}}, + "ZHcy": {Name: "ZHcy", CodePoints: []int{1046}, Characters: []byte{0xd0, 0x96}}, + "Zacute": {Name: "Zacute", CodePoints: []int{377}, Characters: []byte{0xc5, 0xb9}}, + "Zcaron": {Name: "Zcaron", CodePoints: []int{381}, Characters: []byte{0xc5, 0xbd}}, + "Zcy": {Name: "Zcy", CodePoints: []int{1047}, Characters: []byte{0xd0, 0x97}}, + "Zdot": {Name: "Zdot", CodePoints: []int{379}, Characters: []byte{0xc5, 0xbb}}, + "ZeroWidthSpace": {Name: "ZeroWidthSpace", CodePoints: []int{8203}, Characters: []byte{0xe2, 0x80, 0x8b}}, + "Zeta": {Name: "Zeta", CodePoints: []int{918}, Characters: []byte{0xce, 0x96}}, + "Zfr": {Name: "Zfr", CodePoints: []int{8488}, Characters: []byte{0xe2, 0x84, 0xa8}}, + "Zopf": {Name: "Zopf", CodePoints: []int{8484}, Characters: []byte{0xe2, 0x84, 0xa4}}, + "Zscr": {Name: "Zscr", CodePoints: []int{119989}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb5}}, + "aacute": {Name: "aacute", CodePoints: []int{225}, Characters: []byte{0xc3, 0xa1}}, + "abreve": {Name: "abreve", CodePoints: []int{259}, Characters: []byte{0xc4, 0x83}}, + "ac": {Name: "ac", CodePoints: []int{8766}, Characters: []byte{0xe2, 0x88, 0xbe}}, + "acE": {Name: "acE", CodePoints: []int{8766, 819}, Characters: []byte{0xe2, 0x88, 0xbe, 0xcc, 0xb3}}, + "acd": {Name: "acd", CodePoints: []int{8767}, Characters: []byte{0xe2, 0x88, 0xbf}}, + "acirc": {Name: "acirc", CodePoints: []int{226}, Characters: []byte{0xc3, 0xa2}}, + "acute": {Name: "acute", CodePoints: []int{180}, Characters: []byte{0xc2, 0xb4}}, + "acy": {Name: "acy", CodePoints: []int{1072}, Characters: []byte{0xd0, 0xb0}}, + "aelig": {Name: "aelig", CodePoints: []int{230}, Characters: []byte{0xc3, 0xa6}}, + "af": {Name: "af", CodePoints: []int{8289}, Characters: []byte{0xe2, 0x81, 0xa1}}, + "afr": {Name: "afr", CodePoints: []int{120094}, Characters: []byte{0xf0, 0x9d, 0x94, 0x9e}}, + "agrave": {Name: "agrave", CodePoints: []int{224}, Characters: []byte{0xc3, 0xa0}}, + "alefsym": {Name: "alefsym", CodePoints: []int{8501}, Characters: []byte{0xe2, 0x84, 0xb5}}, + "aleph": {Name: "aleph", CodePoints: []int{8501}, Characters: []byte{0xe2, 0x84, 0xb5}}, + "alpha": {Name: "alpha", CodePoints: []int{945}, Characters: []byte{0xce, 0xb1}}, + "amacr": {Name: "amacr", CodePoints: []int{257}, Characters: []byte{0xc4, 0x81}}, + "amalg": {Name: "amalg", CodePoints: []int{10815}, Characters: []byte{0xe2, 0xa8, 0xbf}}, + "amp": {Name: "amp", CodePoints: []int{38}, Characters: []byte{0x26}}, + "and": {Name: "and", CodePoints: []int{8743}, Characters: []byte{0xe2, 0x88, 0xa7}}, + "andand": {Name: "andand", CodePoints: []int{10837}, Characters: []byte{0xe2, 0xa9, 0x95}}, + "andd": {Name: "andd", CodePoints: []int{10844}, Characters: []byte{0xe2, 0xa9, 0x9c}}, + "andslope": {Name: "andslope", CodePoints: []int{10840}, Characters: []byte{0xe2, 0xa9, 0x98}}, + "andv": {Name: "andv", CodePoints: []int{10842}, Characters: []byte{0xe2, 0xa9, 0x9a}}, + "ang": {Name: "ang", CodePoints: []int{8736}, Characters: []byte{0xe2, 0x88, 0xa0}}, + "ange": {Name: "ange", CodePoints: []int{10660}, Characters: []byte{0xe2, 0xa6, 0xa4}}, + "angle": {Name: "angle", CodePoints: []int{8736}, Characters: []byte{0xe2, 0x88, 0xa0}}, + "angmsd": {Name: "angmsd", CodePoints: []int{8737}, Characters: []byte{0xe2, 0x88, 0xa1}}, + "angmsdaa": {Name: "angmsdaa", CodePoints: []int{10664}, Characters: []byte{0xe2, 0xa6, 0xa8}}, + "angmsdab": {Name: "angmsdab", CodePoints: []int{10665}, Characters: []byte{0xe2, 0xa6, 0xa9}}, + "angmsdac": {Name: "angmsdac", CodePoints: []int{10666}, Characters: []byte{0xe2, 0xa6, 0xaa}}, + "angmsdad": {Name: "angmsdad", CodePoints: []int{10667}, Characters: []byte{0xe2, 0xa6, 0xab}}, + "angmsdae": {Name: "angmsdae", CodePoints: []int{10668}, Characters: []byte{0xe2, 0xa6, 0xac}}, + "angmsdaf": {Name: "angmsdaf", CodePoints: []int{10669}, Characters: []byte{0xe2, 0xa6, 0xad}}, + "angmsdag": {Name: "angmsdag", CodePoints: []int{10670}, Characters: []byte{0xe2, 0xa6, 0xae}}, + "angmsdah": {Name: "angmsdah", CodePoints: []int{10671}, Characters: []byte{0xe2, 0xa6, 0xaf}}, + "angrt": {Name: "angrt", CodePoints: []int{8735}, Characters: []byte{0xe2, 0x88, 0x9f}}, + "angrtvb": {Name: "angrtvb", CodePoints: []int{8894}, Characters: []byte{0xe2, 0x8a, 0xbe}}, + "angrtvbd": {Name: "angrtvbd", CodePoints: []int{10653}, Characters: []byte{0xe2, 0xa6, 0x9d}}, + "angsph": {Name: "angsph", CodePoints: []int{8738}, Characters: []byte{0xe2, 0x88, 0xa2}}, + "angst": {Name: "angst", CodePoints: []int{197}, Characters: []byte{0xc3, 0x85}}, + "angzarr": {Name: "angzarr", CodePoints: []int{9084}, Characters: []byte{0xe2, 0x8d, 0xbc}}, + "aogon": {Name: "aogon", CodePoints: []int{261}, Characters: []byte{0xc4, 0x85}}, + "aopf": {Name: "aopf", CodePoints: []int{120146}, Characters: []byte{0xf0, 0x9d, 0x95, 0x92}}, + "ap": {Name: "ap", CodePoints: []int{8776}, Characters: []byte{0xe2, 0x89, 0x88}}, + "apE": {Name: "apE", CodePoints: []int{10864}, Characters: []byte{0xe2, 0xa9, 0xb0}}, + "apacir": {Name: "apacir", CodePoints: []int{10863}, Characters: []byte{0xe2, 0xa9, 0xaf}}, + "ape": {Name: "ape", CodePoints: []int{8778}, Characters: []byte{0xe2, 0x89, 0x8a}}, + "apid": {Name: "apid", CodePoints: []int{8779}, Characters: []byte{0xe2, 0x89, 0x8b}}, + "apos": {Name: "apos", CodePoints: []int{39}, Characters: []byte{0x27}}, + "approx": {Name: "approx", CodePoints: []int{8776}, Characters: []byte{0xe2, 0x89, 0x88}}, + "approxeq": {Name: "approxeq", CodePoints: []int{8778}, Characters: []byte{0xe2, 0x89, 0x8a}}, + "aring": {Name: "aring", CodePoints: []int{229}, Characters: []byte{0xc3, 0xa5}}, + "ascr": {Name: "ascr", CodePoints: []int{119990}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb6}}, + "ast": {Name: "ast", CodePoints: []int{42}, Characters: []byte{0x2a}}, + "asymp": {Name: "asymp", CodePoints: []int{8776}, Characters: []byte{0xe2, 0x89, 0x88}}, + "asympeq": {Name: "asympeq", CodePoints: []int{8781}, Characters: []byte{0xe2, 0x89, 0x8d}}, + "atilde": {Name: "atilde", CodePoints: []int{227}, Characters: []byte{0xc3, 0xa3}}, + "auml": {Name: "auml", CodePoints: []int{228}, Characters: []byte{0xc3, 0xa4}}, + "awconint": {Name: "awconint", CodePoints: []int{8755}, Characters: []byte{0xe2, 0x88, 0xb3}}, + "awint": {Name: "awint", CodePoints: []int{10769}, Characters: []byte{0xe2, 0xa8, 0x91}}, + "bNot": {Name: "bNot", CodePoints: []int{10989}, Characters: []byte{0xe2, 0xab, 0xad}}, + "backcong": {Name: "backcong", CodePoints: []int{8780}, Characters: []byte{0xe2, 0x89, 0x8c}}, + "backepsilon": {Name: "backepsilon", CodePoints: []int{1014}, Characters: []byte{0xcf, 0xb6}}, + "backprime": {Name: "backprime", CodePoints: []int{8245}, Characters: []byte{0xe2, 0x80, 0xb5}}, + "backsim": {Name: "backsim", CodePoints: []int{8765}, Characters: []byte{0xe2, 0x88, 0xbd}}, + "backsimeq": {Name: "backsimeq", CodePoints: []int{8909}, Characters: []byte{0xe2, 0x8b, 0x8d}}, + "barvee": {Name: "barvee", CodePoints: []int{8893}, Characters: []byte{0xe2, 0x8a, 0xbd}}, + "barwed": {Name: "barwed", CodePoints: []int{8965}, Characters: []byte{0xe2, 0x8c, 0x85}}, + "barwedge": {Name: "barwedge", CodePoints: []int{8965}, Characters: []byte{0xe2, 0x8c, 0x85}}, + "bbrk": {Name: "bbrk", CodePoints: []int{9141}, Characters: []byte{0xe2, 0x8e, 0xb5}}, + "bbrktbrk": {Name: "bbrktbrk", CodePoints: []int{9142}, Characters: []byte{0xe2, 0x8e, 0xb6}}, + "bcong": {Name: "bcong", CodePoints: []int{8780}, Characters: []byte{0xe2, 0x89, 0x8c}}, + "bcy": {Name: "bcy", CodePoints: []int{1073}, Characters: []byte{0xd0, 0xb1}}, + "bdquo": {Name: "bdquo", CodePoints: []int{8222}, Characters: []byte{0xe2, 0x80, 0x9e}}, + "becaus": {Name: "becaus", CodePoints: []int{8757}, Characters: []byte{0xe2, 0x88, 0xb5}}, + "because": {Name: "because", CodePoints: []int{8757}, Characters: []byte{0xe2, 0x88, 0xb5}}, + "bemptyv": {Name: "bemptyv", CodePoints: []int{10672}, Characters: []byte{0xe2, 0xa6, 0xb0}}, + "bepsi": {Name: "bepsi", CodePoints: []int{1014}, Characters: []byte{0xcf, 0xb6}}, + "bernou": {Name: "bernou", CodePoints: []int{8492}, Characters: []byte{0xe2, 0x84, 0xac}}, + "beta": {Name: "beta", CodePoints: []int{946}, Characters: []byte{0xce, 0xb2}}, + "beth": {Name: "beth", CodePoints: []int{8502}, Characters: []byte{0xe2, 0x84, 0xb6}}, + "between": {Name: "between", CodePoints: []int{8812}, Characters: []byte{0xe2, 0x89, 0xac}}, + "bfr": {Name: "bfr", CodePoints: []int{120095}, Characters: []byte{0xf0, 0x9d, 0x94, 0x9f}}, + "bigcap": {Name: "bigcap", CodePoints: []int{8898}, Characters: []byte{0xe2, 0x8b, 0x82}}, + "bigcirc": {Name: "bigcirc", CodePoints: []int{9711}, Characters: []byte{0xe2, 0x97, 0xaf}}, + "bigcup": {Name: "bigcup", CodePoints: []int{8899}, Characters: []byte{0xe2, 0x8b, 0x83}}, + "bigodot": {Name: "bigodot", CodePoints: []int{10752}, Characters: []byte{0xe2, 0xa8, 0x80}}, + "bigoplus": {Name: "bigoplus", CodePoints: []int{10753}, Characters: []byte{0xe2, 0xa8, 0x81}}, + "bigotimes": {Name: "bigotimes", CodePoints: []int{10754}, Characters: []byte{0xe2, 0xa8, 0x82}}, + "bigsqcup": {Name: "bigsqcup", CodePoints: []int{10758}, Characters: []byte{0xe2, 0xa8, 0x86}}, + "bigstar": {Name: "bigstar", CodePoints: []int{9733}, Characters: []byte{0xe2, 0x98, 0x85}}, + "bigtriangledown": {Name: "bigtriangledown", CodePoints: []int{9661}, Characters: []byte{0xe2, 0x96, 0xbd}}, + "bigtriangleup": {Name: "bigtriangleup", CodePoints: []int{9651}, Characters: []byte{0xe2, 0x96, 0xb3}}, + "biguplus": {Name: "biguplus", CodePoints: []int{10756}, Characters: []byte{0xe2, 0xa8, 0x84}}, + "bigvee": {Name: "bigvee", CodePoints: []int{8897}, Characters: []byte{0xe2, 0x8b, 0x81}}, + "bigwedge": {Name: "bigwedge", CodePoints: []int{8896}, Characters: []byte{0xe2, 0x8b, 0x80}}, + "bkarow": {Name: "bkarow", CodePoints: []int{10509}, Characters: []byte{0xe2, 0xa4, 0x8d}}, + "blacklozenge": {Name: "blacklozenge", CodePoints: []int{10731}, Characters: []byte{0xe2, 0xa7, 0xab}}, + "blacksquare": {Name: "blacksquare", CodePoints: []int{9642}, Characters: []byte{0xe2, 0x96, 0xaa}}, + "blacktriangle": {Name: "blacktriangle", CodePoints: []int{9652}, Characters: []byte{0xe2, 0x96, 0xb4}}, + "blacktriangledown": {Name: "blacktriangledown", CodePoints: []int{9662}, Characters: []byte{0xe2, 0x96, 0xbe}}, + "blacktriangleleft": {Name: "blacktriangleleft", CodePoints: []int{9666}, Characters: []byte{0xe2, 0x97, 0x82}}, + "blacktriangleright": {Name: "blacktriangleright", CodePoints: []int{9656}, Characters: []byte{0xe2, 0x96, 0xb8}}, + "blank": {Name: "blank", CodePoints: []int{9251}, Characters: []byte{0xe2, 0x90, 0xa3}}, + "blk12": {Name: "blk12", CodePoints: []int{9618}, Characters: []byte{0xe2, 0x96, 0x92}}, + "blk14": {Name: "blk14", CodePoints: []int{9617}, Characters: []byte{0xe2, 0x96, 0x91}}, + "blk34": {Name: "blk34", CodePoints: []int{9619}, Characters: []byte{0xe2, 0x96, 0x93}}, + "block": {Name: "block", CodePoints: []int{9608}, Characters: []byte{0xe2, 0x96, 0x88}}, + "bne": {Name: "bne", CodePoints: []int{61, 8421}, Characters: []byte{0x3d, 0xe2, 0x83, 0xa5}}, + "bnequiv": {Name: "bnequiv", CodePoints: []int{8801, 8421}, Characters: []byte{0xe2, 0x89, 0xa1, 0xe2, 0x83, 0xa5}}, + "bnot": {Name: "bnot", CodePoints: []int{8976}, Characters: []byte{0xe2, 0x8c, 0x90}}, + "bopf": {Name: "bopf", CodePoints: []int{120147}, Characters: []byte{0xf0, 0x9d, 0x95, 0x93}}, + "bot": {Name: "bot", CodePoints: []int{8869}, Characters: []byte{0xe2, 0x8a, 0xa5}}, + "bottom": {Name: "bottom", CodePoints: []int{8869}, Characters: []byte{0xe2, 0x8a, 0xa5}}, + "bowtie": {Name: "bowtie", CodePoints: []int{8904}, Characters: []byte{0xe2, 0x8b, 0x88}}, + "boxDL": {Name: "boxDL", CodePoints: []int{9559}, Characters: []byte{0xe2, 0x95, 0x97}}, + "boxDR": {Name: "boxDR", CodePoints: []int{9556}, Characters: []byte{0xe2, 0x95, 0x94}}, + "boxDl": {Name: "boxDl", CodePoints: []int{9558}, Characters: []byte{0xe2, 0x95, 0x96}}, + "boxDr": {Name: "boxDr", CodePoints: []int{9555}, Characters: []byte{0xe2, 0x95, 0x93}}, + "boxH": {Name: "boxH", CodePoints: []int{9552}, Characters: []byte{0xe2, 0x95, 0x90}}, + "boxHD": {Name: "boxHD", CodePoints: []int{9574}, Characters: []byte{0xe2, 0x95, 0xa6}}, + "boxHU": {Name: "boxHU", CodePoints: []int{9577}, Characters: []byte{0xe2, 0x95, 0xa9}}, + "boxHd": {Name: "boxHd", CodePoints: []int{9572}, Characters: []byte{0xe2, 0x95, 0xa4}}, + "boxHu": {Name: "boxHu", CodePoints: []int{9575}, Characters: []byte{0xe2, 0x95, 0xa7}}, + "boxUL": {Name: "boxUL", CodePoints: []int{9565}, Characters: []byte{0xe2, 0x95, 0x9d}}, + "boxUR": {Name: "boxUR", CodePoints: []int{9562}, Characters: []byte{0xe2, 0x95, 0x9a}}, + "boxUl": {Name: "boxUl", CodePoints: []int{9564}, Characters: []byte{0xe2, 0x95, 0x9c}}, + "boxUr": {Name: "boxUr", CodePoints: []int{9561}, Characters: []byte{0xe2, 0x95, 0x99}}, + "boxV": {Name: "boxV", CodePoints: []int{9553}, Characters: []byte{0xe2, 0x95, 0x91}}, + "boxVH": {Name: "boxVH", CodePoints: []int{9580}, Characters: []byte{0xe2, 0x95, 0xac}}, + "boxVL": {Name: "boxVL", CodePoints: []int{9571}, Characters: []byte{0xe2, 0x95, 0xa3}}, + "boxVR": {Name: "boxVR", CodePoints: []int{9568}, Characters: []byte{0xe2, 0x95, 0xa0}}, + "boxVh": {Name: "boxVh", CodePoints: []int{9579}, Characters: []byte{0xe2, 0x95, 0xab}}, + "boxVl": {Name: "boxVl", CodePoints: []int{9570}, Characters: []byte{0xe2, 0x95, 0xa2}}, + "boxVr": {Name: "boxVr", CodePoints: []int{9567}, Characters: []byte{0xe2, 0x95, 0x9f}}, + "boxbox": {Name: "boxbox", CodePoints: []int{10697}, Characters: []byte{0xe2, 0xa7, 0x89}}, + "boxdL": {Name: "boxdL", CodePoints: []int{9557}, Characters: []byte{0xe2, 0x95, 0x95}}, + "boxdR": {Name: "boxdR", CodePoints: []int{9554}, Characters: []byte{0xe2, 0x95, 0x92}}, + "boxdl": {Name: "boxdl", CodePoints: []int{9488}, Characters: []byte{0xe2, 0x94, 0x90}}, + "boxdr": {Name: "boxdr", CodePoints: []int{9484}, Characters: []byte{0xe2, 0x94, 0x8c}}, + "boxh": {Name: "boxh", CodePoints: []int{9472}, Characters: []byte{0xe2, 0x94, 0x80}}, + "boxhD": {Name: "boxhD", CodePoints: []int{9573}, Characters: []byte{0xe2, 0x95, 0xa5}}, + "boxhU": {Name: "boxhU", CodePoints: []int{9576}, Characters: []byte{0xe2, 0x95, 0xa8}}, + "boxhd": {Name: "boxhd", CodePoints: []int{9516}, Characters: []byte{0xe2, 0x94, 0xac}}, + "boxhu": {Name: "boxhu", CodePoints: []int{9524}, Characters: []byte{0xe2, 0x94, 0xb4}}, + "boxminus": {Name: "boxminus", CodePoints: []int{8863}, Characters: []byte{0xe2, 0x8a, 0x9f}}, + "boxplus": {Name: "boxplus", CodePoints: []int{8862}, Characters: []byte{0xe2, 0x8a, 0x9e}}, + "boxtimes": {Name: "boxtimes", CodePoints: []int{8864}, Characters: []byte{0xe2, 0x8a, 0xa0}}, + "boxuL": {Name: "boxuL", CodePoints: []int{9563}, Characters: []byte{0xe2, 0x95, 0x9b}}, + "boxuR": {Name: "boxuR", CodePoints: []int{9560}, Characters: []byte{0xe2, 0x95, 0x98}}, + "boxul": {Name: "boxul", CodePoints: []int{9496}, Characters: []byte{0xe2, 0x94, 0x98}}, + "boxur": {Name: "boxur", CodePoints: []int{9492}, Characters: []byte{0xe2, 0x94, 0x94}}, + "boxv": {Name: "boxv", CodePoints: []int{9474}, Characters: []byte{0xe2, 0x94, 0x82}}, + "boxvH": {Name: "boxvH", CodePoints: []int{9578}, Characters: []byte{0xe2, 0x95, 0xaa}}, + "boxvL": {Name: "boxvL", CodePoints: []int{9569}, Characters: []byte{0xe2, 0x95, 0xa1}}, + "boxvR": {Name: "boxvR", CodePoints: []int{9566}, Characters: []byte{0xe2, 0x95, 0x9e}}, + "boxvh": {Name: "boxvh", CodePoints: []int{9532}, Characters: []byte{0xe2, 0x94, 0xbc}}, + "boxvl": {Name: "boxvl", CodePoints: []int{9508}, Characters: []byte{0xe2, 0x94, 0xa4}}, + "boxvr": {Name: "boxvr", CodePoints: []int{9500}, Characters: []byte{0xe2, 0x94, 0x9c}}, + "bprime": {Name: "bprime", CodePoints: []int{8245}, Characters: []byte{0xe2, 0x80, 0xb5}}, + "breve": {Name: "breve", CodePoints: []int{728}, Characters: []byte{0xcb, 0x98}}, + "brvbar": {Name: "brvbar", CodePoints: []int{166}, Characters: []byte{0xc2, 0xa6}}, + "bscr": {Name: "bscr", CodePoints: []int{119991}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb7}}, + "bsemi": {Name: "bsemi", CodePoints: []int{8271}, Characters: []byte{0xe2, 0x81, 0x8f}}, + "bsim": {Name: "bsim", CodePoints: []int{8765}, Characters: []byte{0xe2, 0x88, 0xbd}}, + "bsime": {Name: "bsime", CodePoints: []int{8909}, Characters: []byte{0xe2, 0x8b, 0x8d}}, + "bsol": {Name: "bsol", CodePoints: []int{92}, Characters: []byte{0x5c}}, + "bsolb": {Name: "bsolb", CodePoints: []int{10693}, Characters: []byte{0xe2, 0xa7, 0x85}}, + "bsolhsub": {Name: "bsolhsub", CodePoints: []int{10184}, Characters: []byte{0xe2, 0x9f, 0x88}}, + "bull": {Name: "bull", CodePoints: []int{8226}, Characters: []byte{0xe2, 0x80, 0xa2}}, + "bullet": {Name: "bullet", CodePoints: []int{8226}, Characters: []byte{0xe2, 0x80, 0xa2}}, + "bump": {Name: "bump", CodePoints: []int{8782}, Characters: []byte{0xe2, 0x89, 0x8e}}, + "bumpE": {Name: "bumpE", CodePoints: []int{10926}, Characters: []byte{0xe2, 0xaa, 0xae}}, + "bumpe": {Name: "bumpe", CodePoints: []int{8783}, Characters: []byte{0xe2, 0x89, 0x8f}}, + "bumpeq": {Name: "bumpeq", CodePoints: []int{8783}, Characters: []byte{0xe2, 0x89, 0x8f}}, + "cacute": {Name: "cacute", CodePoints: []int{263}, Characters: []byte{0xc4, 0x87}}, + "cap": {Name: "cap", CodePoints: []int{8745}, Characters: []byte{0xe2, 0x88, 0xa9}}, + "capand": {Name: "capand", CodePoints: []int{10820}, Characters: []byte{0xe2, 0xa9, 0x84}}, + "capbrcup": {Name: "capbrcup", CodePoints: []int{10825}, Characters: []byte{0xe2, 0xa9, 0x89}}, + "capcap": {Name: "capcap", CodePoints: []int{10827}, Characters: []byte{0xe2, 0xa9, 0x8b}}, + "capcup": {Name: "capcup", CodePoints: []int{10823}, Characters: []byte{0xe2, 0xa9, 0x87}}, + "capdot": {Name: "capdot", CodePoints: []int{10816}, Characters: []byte{0xe2, 0xa9, 0x80}}, + "caps": {Name: "caps", CodePoints: []int{8745, 65024}, Characters: []byte{0xe2, 0x88, 0xa9, 0xef, 0xb8, 0x80}}, + "caret": {Name: "caret", CodePoints: []int{8257}, Characters: []byte{0xe2, 0x81, 0x81}}, + "caron": {Name: "caron", CodePoints: []int{711}, Characters: []byte{0xcb, 0x87}}, + "ccaps": {Name: "ccaps", CodePoints: []int{10829}, Characters: []byte{0xe2, 0xa9, 0x8d}}, + "ccaron": {Name: "ccaron", CodePoints: []int{269}, Characters: []byte{0xc4, 0x8d}}, + "ccedil": {Name: "ccedil", CodePoints: []int{231}, Characters: []byte{0xc3, 0xa7}}, + "ccirc": {Name: "ccirc", CodePoints: []int{265}, Characters: []byte{0xc4, 0x89}}, + "ccups": {Name: "ccups", CodePoints: []int{10828}, Characters: []byte{0xe2, 0xa9, 0x8c}}, + "ccupssm": {Name: "ccupssm", CodePoints: []int{10832}, Characters: []byte{0xe2, 0xa9, 0x90}}, + "cdot": {Name: "cdot", CodePoints: []int{267}, Characters: []byte{0xc4, 0x8b}}, + "cedil": {Name: "cedil", CodePoints: []int{184}, Characters: []byte{0xc2, 0xb8}}, + "cemptyv": {Name: "cemptyv", CodePoints: []int{10674}, Characters: []byte{0xe2, 0xa6, 0xb2}}, + "cent": {Name: "cent", CodePoints: []int{162}, Characters: []byte{0xc2, 0xa2}}, + "centerdot": {Name: "centerdot", CodePoints: []int{183}, Characters: []byte{0xc2, 0xb7}}, + "cfr": {Name: "cfr", CodePoints: []int{120096}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa0}}, + "chcy": {Name: "chcy", CodePoints: []int{1095}, Characters: []byte{0xd1, 0x87}}, + "check": {Name: "check", CodePoints: []int{10003}, Characters: []byte{0xe2, 0x9c, 0x93}}, + "checkmark": {Name: "checkmark", CodePoints: []int{10003}, Characters: []byte{0xe2, 0x9c, 0x93}}, + "chi": {Name: "chi", CodePoints: []int{967}, Characters: []byte{0xcf, 0x87}}, + "cir": {Name: "cir", CodePoints: []int{9675}, Characters: []byte{0xe2, 0x97, 0x8b}}, + "cirE": {Name: "cirE", CodePoints: []int{10691}, Characters: []byte{0xe2, 0xa7, 0x83}}, + "circ": {Name: "circ", CodePoints: []int{710}, Characters: []byte{0xcb, 0x86}}, + "circeq": {Name: "circeq", CodePoints: []int{8791}, Characters: []byte{0xe2, 0x89, 0x97}}, + "circlearrowleft": {Name: "circlearrowleft", CodePoints: []int{8634}, Characters: []byte{0xe2, 0x86, 0xba}}, + "circlearrowright": {Name: "circlearrowright", CodePoints: []int{8635}, Characters: []byte{0xe2, 0x86, 0xbb}}, + "circledR": {Name: "circledR", CodePoints: []int{174}, Characters: []byte{0xc2, 0xae}}, + "circledS": {Name: "circledS", CodePoints: []int{9416}, Characters: []byte{0xe2, 0x93, 0x88}}, + "circledast": {Name: "circledast", CodePoints: []int{8859}, Characters: []byte{0xe2, 0x8a, 0x9b}}, + "circledcirc": {Name: "circledcirc", CodePoints: []int{8858}, Characters: []byte{0xe2, 0x8a, 0x9a}}, + "circleddash": {Name: "circleddash", CodePoints: []int{8861}, Characters: []byte{0xe2, 0x8a, 0x9d}}, + "cire": {Name: "cire", CodePoints: []int{8791}, Characters: []byte{0xe2, 0x89, 0x97}}, + "cirfnint": {Name: "cirfnint", CodePoints: []int{10768}, Characters: []byte{0xe2, 0xa8, 0x90}}, + "cirmid": {Name: "cirmid", CodePoints: []int{10991}, Characters: []byte{0xe2, 0xab, 0xaf}}, + "cirscir": {Name: "cirscir", CodePoints: []int{10690}, Characters: []byte{0xe2, 0xa7, 0x82}}, + "clubs": {Name: "clubs", CodePoints: []int{9827}, Characters: []byte{0xe2, 0x99, 0xa3}}, + "clubsuit": {Name: "clubsuit", CodePoints: []int{9827}, Characters: []byte{0xe2, 0x99, 0xa3}}, + "colon": {Name: "colon", CodePoints: []int{58}, Characters: []byte{0x3a}}, + "colone": {Name: "colone", CodePoints: []int{8788}, Characters: []byte{0xe2, 0x89, 0x94}}, + "coloneq": {Name: "coloneq", CodePoints: []int{8788}, Characters: []byte{0xe2, 0x89, 0x94}}, + "comma": {Name: "comma", CodePoints: []int{44}, Characters: []byte{0x2c}}, + "commat": {Name: "commat", CodePoints: []int{64}, Characters: []byte{0x40}}, + "comp": {Name: "comp", CodePoints: []int{8705}, Characters: []byte{0xe2, 0x88, 0x81}}, + "compfn": {Name: "compfn", CodePoints: []int{8728}, Characters: []byte{0xe2, 0x88, 0x98}}, + "complement": {Name: "complement", CodePoints: []int{8705}, Characters: []byte{0xe2, 0x88, 0x81}}, + "complexes": {Name: "complexes", CodePoints: []int{8450}, Characters: []byte{0xe2, 0x84, 0x82}}, + "cong": {Name: "cong", CodePoints: []int{8773}, Characters: []byte{0xe2, 0x89, 0x85}}, + "congdot": {Name: "congdot", CodePoints: []int{10861}, Characters: []byte{0xe2, 0xa9, 0xad}}, + "conint": {Name: "conint", CodePoints: []int{8750}, Characters: []byte{0xe2, 0x88, 0xae}}, + "copf": {Name: "copf", CodePoints: []int{120148}, Characters: []byte{0xf0, 0x9d, 0x95, 0x94}}, + "coprod": {Name: "coprod", CodePoints: []int{8720}, Characters: []byte{0xe2, 0x88, 0x90}}, + "copy": {Name: "copy", CodePoints: []int{169}, Characters: []byte{0xc2, 0xa9}}, + "copysr": {Name: "copysr", CodePoints: []int{8471}, Characters: []byte{0xe2, 0x84, 0x97}}, + "crarr": {Name: "crarr", CodePoints: []int{8629}, Characters: []byte{0xe2, 0x86, 0xb5}}, + "cross": {Name: "cross", CodePoints: []int{10007}, Characters: []byte{0xe2, 0x9c, 0x97}}, + "cscr": {Name: "cscr", CodePoints: []int{119992}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb8}}, + "csub": {Name: "csub", CodePoints: []int{10959}, Characters: []byte{0xe2, 0xab, 0x8f}}, + "csube": {Name: "csube", CodePoints: []int{10961}, Characters: []byte{0xe2, 0xab, 0x91}}, + "csup": {Name: "csup", CodePoints: []int{10960}, Characters: []byte{0xe2, 0xab, 0x90}}, + "csupe": {Name: "csupe", CodePoints: []int{10962}, Characters: []byte{0xe2, 0xab, 0x92}}, + "ctdot": {Name: "ctdot", CodePoints: []int{8943}, Characters: []byte{0xe2, 0x8b, 0xaf}}, + "cudarrl": {Name: "cudarrl", CodePoints: []int{10552}, Characters: []byte{0xe2, 0xa4, 0xb8}}, + "cudarrr": {Name: "cudarrr", CodePoints: []int{10549}, Characters: []byte{0xe2, 0xa4, 0xb5}}, + "cuepr": {Name: "cuepr", CodePoints: []int{8926}, Characters: []byte{0xe2, 0x8b, 0x9e}}, + "cuesc": {Name: "cuesc", CodePoints: []int{8927}, Characters: []byte{0xe2, 0x8b, 0x9f}}, + "cularr": {Name: "cularr", CodePoints: []int{8630}, Characters: []byte{0xe2, 0x86, 0xb6}}, + "cularrp": {Name: "cularrp", CodePoints: []int{10557}, Characters: []byte{0xe2, 0xa4, 0xbd}}, + "cup": {Name: "cup", CodePoints: []int{8746}, Characters: []byte{0xe2, 0x88, 0xaa}}, + "cupbrcap": {Name: "cupbrcap", CodePoints: []int{10824}, Characters: []byte{0xe2, 0xa9, 0x88}}, + "cupcap": {Name: "cupcap", CodePoints: []int{10822}, Characters: []byte{0xe2, 0xa9, 0x86}}, + "cupcup": {Name: "cupcup", CodePoints: []int{10826}, Characters: []byte{0xe2, 0xa9, 0x8a}}, + "cupdot": {Name: "cupdot", CodePoints: []int{8845}, Characters: []byte{0xe2, 0x8a, 0x8d}}, + "cupor": {Name: "cupor", CodePoints: []int{10821}, Characters: []byte{0xe2, 0xa9, 0x85}}, + "cups": {Name: "cups", CodePoints: []int{8746, 65024}, Characters: []byte{0xe2, 0x88, 0xaa, 0xef, 0xb8, 0x80}}, + "curarr": {Name: "curarr", CodePoints: []int{8631}, Characters: []byte{0xe2, 0x86, 0xb7}}, + "curarrm": {Name: "curarrm", CodePoints: []int{10556}, Characters: []byte{0xe2, 0xa4, 0xbc}}, + "curlyeqprec": {Name: "curlyeqprec", CodePoints: []int{8926}, Characters: []byte{0xe2, 0x8b, 0x9e}}, + "curlyeqsucc": {Name: "curlyeqsucc", CodePoints: []int{8927}, Characters: []byte{0xe2, 0x8b, 0x9f}}, + "curlyvee": {Name: "curlyvee", CodePoints: []int{8910}, Characters: []byte{0xe2, 0x8b, 0x8e}}, + "curlywedge": {Name: "curlywedge", CodePoints: []int{8911}, Characters: []byte{0xe2, 0x8b, 0x8f}}, + "curren": {Name: "curren", CodePoints: []int{164}, Characters: []byte{0xc2, 0xa4}}, + "curvearrowleft": {Name: "curvearrowleft", CodePoints: []int{8630}, Characters: []byte{0xe2, 0x86, 0xb6}}, + "curvearrowright": {Name: "curvearrowright", CodePoints: []int{8631}, Characters: []byte{0xe2, 0x86, 0xb7}}, + "cuvee": {Name: "cuvee", CodePoints: []int{8910}, Characters: []byte{0xe2, 0x8b, 0x8e}}, + "cuwed": {Name: "cuwed", CodePoints: []int{8911}, Characters: []byte{0xe2, 0x8b, 0x8f}}, + "cwconint": {Name: "cwconint", CodePoints: []int{8754}, Characters: []byte{0xe2, 0x88, 0xb2}}, + "cwint": {Name: "cwint", CodePoints: []int{8753}, Characters: []byte{0xe2, 0x88, 0xb1}}, + "cylcty": {Name: "cylcty", CodePoints: []int{9005}, Characters: []byte{0xe2, 0x8c, 0xad}}, + "dArr": {Name: "dArr", CodePoints: []int{8659}, Characters: []byte{0xe2, 0x87, 0x93}}, + "dHar": {Name: "dHar", CodePoints: []int{10597}, Characters: []byte{0xe2, 0xa5, 0xa5}}, + "dagger": {Name: "dagger", CodePoints: []int{8224}, Characters: []byte{0xe2, 0x80, 0xa0}}, + "daleth": {Name: "daleth", CodePoints: []int{8504}, Characters: []byte{0xe2, 0x84, 0xb8}}, + "darr": {Name: "darr", CodePoints: []int{8595}, Characters: []byte{0xe2, 0x86, 0x93}}, + "dash": {Name: "dash", CodePoints: []int{8208}, Characters: []byte{0xe2, 0x80, 0x90}}, + "dashv": {Name: "dashv", CodePoints: []int{8867}, Characters: []byte{0xe2, 0x8a, 0xa3}}, + "dbkarow": {Name: "dbkarow", CodePoints: []int{10511}, Characters: []byte{0xe2, 0xa4, 0x8f}}, + "dblac": {Name: "dblac", CodePoints: []int{733}, Characters: []byte{0xcb, 0x9d}}, + "dcaron": {Name: "dcaron", CodePoints: []int{271}, Characters: []byte{0xc4, 0x8f}}, + "dcy": {Name: "dcy", CodePoints: []int{1076}, Characters: []byte{0xd0, 0xb4}}, + "dd": {Name: "dd", CodePoints: []int{8518}, Characters: []byte{0xe2, 0x85, 0x86}}, + "ddagger": {Name: "ddagger", CodePoints: []int{8225}, Characters: []byte{0xe2, 0x80, 0xa1}}, + "ddarr": {Name: "ddarr", CodePoints: []int{8650}, Characters: []byte{0xe2, 0x87, 0x8a}}, + "ddotseq": {Name: "ddotseq", CodePoints: []int{10871}, Characters: []byte{0xe2, 0xa9, 0xb7}}, + "deg": {Name: "deg", CodePoints: []int{176}, Characters: []byte{0xc2, 0xb0}}, + "delta": {Name: "delta", CodePoints: []int{948}, Characters: []byte{0xce, 0xb4}}, + "demptyv": {Name: "demptyv", CodePoints: []int{10673}, Characters: []byte{0xe2, 0xa6, 0xb1}}, + "dfisht": {Name: "dfisht", CodePoints: []int{10623}, Characters: []byte{0xe2, 0xa5, 0xbf}}, + "dfr": {Name: "dfr", CodePoints: []int{120097}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa1}}, + "dharl": {Name: "dharl", CodePoints: []int{8643}, Characters: []byte{0xe2, 0x87, 0x83}}, + "dharr": {Name: "dharr", CodePoints: []int{8642}, Characters: []byte{0xe2, 0x87, 0x82}}, + "diam": {Name: "diam", CodePoints: []int{8900}, Characters: []byte{0xe2, 0x8b, 0x84}}, + "diamond": {Name: "diamond", CodePoints: []int{8900}, Characters: []byte{0xe2, 0x8b, 0x84}}, + "diamondsuit": {Name: "diamondsuit", CodePoints: []int{9830}, Characters: []byte{0xe2, 0x99, 0xa6}}, + "diams": {Name: "diams", CodePoints: []int{9830}, Characters: []byte{0xe2, 0x99, 0xa6}}, + "die": {Name: "die", CodePoints: []int{168}, Characters: []byte{0xc2, 0xa8}}, + "digamma": {Name: "digamma", CodePoints: []int{989}, Characters: []byte{0xcf, 0x9d}}, + "disin": {Name: "disin", CodePoints: []int{8946}, Characters: []byte{0xe2, 0x8b, 0xb2}}, + "div": {Name: "div", CodePoints: []int{247}, Characters: []byte{0xc3, 0xb7}}, + "divide": {Name: "divide", CodePoints: []int{247}, Characters: []byte{0xc3, 0xb7}}, + "divideontimes": {Name: "divideontimes", CodePoints: []int{8903}, Characters: []byte{0xe2, 0x8b, 0x87}}, + "divonx": {Name: "divonx", CodePoints: []int{8903}, Characters: []byte{0xe2, 0x8b, 0x87}}, + "djcy": {Name: "djcy", CodePoints: []int{1106}, Characters: []byte{0xd1, 0x92}}, + "dlcorn": {Name: "dlcorn", CodePoints: []int{8990}, Characters: []byte{0xe2, 0x8c, 0x9e}}, + "dlcrop": {Name: "dlcrop", CodePoints: []int{8973}, Characters: []byte{0xe2, 0x8c, 0x8d}}, + "dollar": {Name: "dollar", CodePoints: []int{36}, Characters: []byte{0x24}}, + "dopf": {Name: "dopf", CodePoints: []int{120149}, Characters: []byte{0xf0, 0x9d, 0x95, 0x95}}, + "dot": {Name: "dot", CodePoints: []int{729}, Characters: []byte{0xcb, 0x99}}, + "doteq": {Name: "doteq", CodePoints: []int{8784}, Characters: []byte{0xe2, 0x89, 0x90}}, + "doteqdot": {Name: "doteqdot", CodePoints: []int{8785}, Characters: []byte{0xe2, 0x89, 0x91}}, + "dotminus": {Name: "dotminus", CodePoints: []int{8760}, Characters: []byte{0xe2, 0x88, 0xb8}}, + "dotplus": {Name: "dotplus", CodePoints: []int{8724}, Characters: []byte{0xe2, 0x88, 0x94}}, + "dotsquare": {Name: "dotsquare", CodePoints: []int{8865}, Characters: []byte{0xe2, 0x8a, 0xa1}}, + "doublebarwedge": {Name: "doublebarwedge", CodePoints: []int{8966}, Characters: []byte{0xe2, 0x8c, 0x86}}, + "downarrow": {Name: "downarrow", CodePoints: []int{8595}, Characters: []byte{0xe2, 0x86, 0x93}}, + "downdownarrows": {Name: "downdownarrows", CodePoints: []int{8650}, Characters: []byte{0xe2, 0x87, 0x8a}}, + "downharpoonleft": {Name: "downharpoonleft", CodePoints: []int{8643}, Characters: []byte{0xe2, 0x87, 0x83}}, + "downharpoonright": {Name: "downharpoonright", CodePoints: []int{8642}, Characters: []byte{0xe2, 0x87, 0x82}}, + "drbkarow": {Name: "drbkarow", CodePoints: []int{10512}, Characters: []byte{0xe2, 0xa4, 0x90}}, + "drcorn": {Name: "drcorn", CodePoints: []int{8991}, Characters: []byte{0xe2, 0x8c, 0x9f}}, + "drcrop": {Name: "drcrop", CodePoints: []int{8972}, Characters: []byte{0xe2, 0x8c, 0x8c}}, + "dscr": {Name: "dscr", CodePoints: []int{119993}, Characters: []byte{0xf0, 0x9d, 0x92, 0xb9}}, + "dscy": {Name: "dscy", CodePoints: []int{1109}, Characters: []byte{0xd1, 0x95}}, + "dsol": {Name: "dsol", CodePoints: []int{10742}, Characters: []byte{0xe2, 0xa7, 0xb6}}, + "dstrok": {Name: "dstrok", CodePoints: []int{273}, Characters: []byte{0xc4, 0x91}}, + "dtdot": {Name: "dtdot", CodePoints: []int{8945}, Characters: []byte{0xe2, 0x8b, 0xb1}}, + "dtri": {Name: "dtri", CodePoints: []int{9663}, Characters: []byte{0xe2, 0x96, 0xbf}}, + "dtrif": {Name: "dtrif", CodePoints: []int{9662}, Characters: []byte{0xe2, 0x96, 0xbe}}, + "duarr": {Name: "duarr", CodePoints: []int{8693}, Characters: []byte{0xe2, 0x87, 0xb5}}, + "duhar": {Name: "duhar", CodePoints: []int{10607}, Characters: []byte{0xe2, 0xa5, 0xaf}}, + "dwangle": {Name: "dwangle", CodePoints: []int{10662}, Characters: []byte{0xe2, 0xa6, 0xa6}}, + "dzcy": {Name: "dzcy", CodePoints: []int{1119}, Characters: []byte{0xd1, 0x9f}}, + "dzigrarr": {Name: "dzigrarr", CodePoints: []int{10239}, Characters: []byte{0xe2, 0x9f, 0xbf}}, + "eDDot": {Name: "eDDot", CodePoints: []int{10871}, Characters: []byte{0xe2, 0xa9, 0xb7}}, + "eDot": {Name: "eDot", CodePoints: []int{8785}, Characters: []byte{0xe2, 0x89, 0x91}}, + "eacute": {Name: "eacute", CodePoints: []int{233}, Characters: []byte{0xc3, 0xa9}}, + "easter": {Name: "easter", CodePoints: []int{10862}, Characters: []byte{0xe2, 0xa9, 0xae}}, + "ecaron": {Name: "ecaron", CodePoints: []int{283}, Characters: []byte{0xc4, 0x9b}}, + "ecir": {Name: "ecir", CodePoints: []int{8790}, Characters: []byte{0xe2, 0x89, 0x96}}, + "ecirc": {Name: "ecirc", CodePoints: []int{234}, Characters: []byte{0xc3, 0xaa}}, + "ecolon": {Name: "ecolon", CodePoints: []int{8789}, Characters: []byte{0xe2, 0x89, 0x95}}, + "ecy": {Name: "ecy", CodePoints: []int{1101}, Characters: []byte{0xd1, 0x8d}}, + "edot": {Name: "edot", CodePoints: []int{279}, Characters: []byte{0xc4, 0x97}}, + "ee": {Name: "ee", CodePoints: []int{8519}, Characters: []byte{0xe2, 0x85, 0x87}}, + "efDot": {Name: "efDot", CodePoints: []int{8786}, Characters: []byte{0xe2, 0x89, 0x92}}, + "efr": {Name: "efr", CodePoints: []int{120098}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa2}}, + "eg": {Name: "eg", CodePoints: []int{10906}, Characters: []byte{0xe2, 0xaa, 0x9a}}, + "egrave": {Name: "egrave", CodePoints: []int{232}, Characters: []byte{0xc3, 0xa8}}, + "egs": {Name: "egs", CodePoints: []int{10902}, Characters: []byte{0xe2, 0xaa, 0x96}}, + "egsdot": {Name: "egsdot", CodePoints: []int{10904}, Characters: []byte{0xe2, 0xaa, 0x98}}, + "el": {Name: "el", CodePoints: []int{10905}, Characters: []byte{0xe2, 0xaa, 0x99}}, + "elinters": {Name: "elinters", CodePoints: []int{9191}, Characters: []byte{0xe2, 0x8f, 0xa7}}, + "ell": {Name: "ell", CodePoints: []int{8467}, Characters: []byte{0xe2, 0x84, 0x93}}, + "els": {Name: "els", CodePoints: []int{10901}, Characters: []byte{0xe2, 0xaa, 0x95}}, + "elsdot": {Name: "elsdot", CodePoints: []int{10903}, Characters: []byte{0xe2, 0xaa, 0x97}}, + "emacr": {Name: "emacr", CodePoints: []int{275}, Characters: []byte{0xc4, 0x93}}, + "empty": {Name: "empty", CodePoints: []int{8709}, Characters: []byte{0xe2, 0x88, 0x85}}, + "emptyset": {Name: "emptyset", CodePoints: []int{8709}, Characters: []byte{0xe2, 0x88, 0x85}}, + "emptyv": {Name: "emptyv", CodePoints: []int{8709}, Characters: []byte{0xe2, 0x88, 0x85}}, + "emsp": {Name: "emsp", CodePoints: []int{8195}, Characters: []byte{0xe2, 0x80, 0x83}}, + "emsp13": {Name: "emsp13", CodePoints: []int{8196}, Characters: []byte{0xe2, 0x80, 0x84}}, + "emsp14": {Name: "emsp14", CodePoints: []int{8197}, Characters: []byte{0xe2, 0x80, 0x85}}, + "eng": {Name: "eng", CodePoints: []int{331}, Characters: []byte{0xc5, 0x8b}}, + "ensp": {Name: "ensp", CodePoints: []int{8194}, Characters: []byte{0xe2, 0x80, 0x82}}, + "eogon": {Name: "eogon", CodePoints: []int{281}, Characters: []byte{0xc4, 0x99}}, + "eopf": {Name: "eopf", CodePoints: []int{120150}, Characters: []byte{0xf0, 0x9d, 0x95, 0x96}}, + "epar": {Name: "epar", CodePoints: []int{8917}, Characters: []byte{0xe2, 0x8b, 0x95}}, + "eparsl": {Name: "eparsl", CodePoints: []int{10723}, Characters: []byte{0xe2, 0xa7, 0xa3}}, + "eplus": {Name: "eplus", CodePoints: []int{10865}, Characters: []byte{0xe2, 0xa9, 0xb1}}, + "epsi": {Name: "epsi", CodePoints: []int{949}, Characters: []byte{0xce, 0xb5}}, + "epsilon": {Name: "epsilon", CodePoints: []int{949}, Characters: []byte{0xce, 0xb5}}, + "epsiv": {Name: "epsiv", CodePoints: []int{1013}, Characters: []byte{0xcf, 0xb5}}, + "eqcirc": {Name: "eqcirc", CodePoints: []int{8790}, Characters: []byte{0xe2, 0x89, 0x96}}, + "eqcolon": {Name: "eqcolon", CodePoints: []int{8789}, Characters: []byte{0xe2, 0x89, 0x95}}, + "eqsim": {Name: "eqsim", CodePoints: []int{8770}, Characters: []byte{0xe2, 0x89, 0x82}}, + "eqslantgtr": {Name: "eqslantgtr", CodePoints: []int{10902}, Characters: []byte{0xe2, 0xaa, 0x96}}, + "eqslantless": {Name: "eqslantless", CodePoints: []int{10901}, Characters: []byte{0xe2, 0xaa, 0x95}}, + "equals": {Name: "equals", CodePoints: []int{61}, Characters: []byte{0x3d}}, + "equest": {Name: "equest", CodePoints: []int{8799}, Characters: []byte{0xe2, 0x89, 0x9f}}, + "equiv": {Name: "equiv", CodePoints: []int{8801}, Characters: []byte{0xe2, 0x89, 0xa1}}, + "equivDD": {Name: "equivDD", CodePoints: []int{10872}, Characters: []byte{0xe2, 0xa9, 0xb8}}, + "eqvparsl": {Name: "eqvparsl", CodePoints: []int{10725}, Characters: []byte{0xe2, 0xa7, 0xa5}}, + "erDot": {Name: "erDot", CodePoints: []int{8787}, Characters: []byte{0xe2, 0x89, 0x93}}, + "erarr": {Name: "erarr", CodePoints: []int{10609}, Characters: []byte{0xe2, 0xa5, 0xb1}}, + "escr": {Name: "escr", CodePoints: []int{8495}, Characters: []byte{0xe2, 0x84, 0xaf}}, + "esdot": {Name: "esdot", CodePoints: []int{8784}, Characters: []byte{0xe2, 0x89, 0x90}}, + "esim": {Name: "esim", CodePoints: []int{8770}, Characters: []byte{0xe2, 0x89, 0x82}}, + "eta": {Name: "eta", CodePoints: []int{951}, Characters: []byte{0xce, 0xb7}}, + "eth": {Name: "eth", CodePoints: []int{240}, Characters: []byte{0xc3, 0xb0}}, + "euml": {Name: "euml", CodePoints: []int{235}, Characters: []byte{0xc3, 0xab}}, + "euro": {Name: "euro", CodePoints: []int{8364}, Characters: []byte{0xe2, 0x82, 0xac}}, + "excl": {Name: "excl", CodePoints: []int{33}, Characters: []byte{0x21}}, + "exist": {Name: "exist", CodePoints: []int{8707}, Characters: []byte{0xe2, 0x88, 0x83}}, + "expectation": {Name: "expectation", CodePoints: []int{8496}, Characters: []byte{0xe2, 0x84, 0xb0}}, + "exponentiale": {Name: "exponentiale", CodePoints: []int{8519}, Characters: []byte{0xe2, 0x85, 0x87}}, + "fallingdotseq": {Name: "fallingdotseq", CodePoints: []int{8786}, Characters: []byte{0xe2, 0x89, 0x92}}, + "fcy": {Name: "fcy", CodePoints: []int{1092}, Characters: []byte{0xd1, 0x84}}, + "female": {Name: "female", CodePoints: []int{9792}, Characters: []byte{0xe2, 0x99, 0x80}}, + "ffilig": {Name: "ffilig", CodePoints: []int{64259}, Characters: []byte{0xef, 0xac, 0x83}}, + "fflig": {Name: "fflig", CodePoints: []int{64256}, Characters: []byte{0xef, 0xac, 0x80}}, + "ffllig": {Name: "ffllig", CodePoints: []int{64260}, Characters: []byte{0xef, 0xac, 0x84}}, + "ffr": {Name: "ffr", CodePoints: []int{120099}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa3}}, + "filig": {Name: "filig", CodePoints: []int{64257}, Characters: []byte{0xef, 0xac, 0x81}}, + "fjlig": {Name: "fjlig", CodePoints: []int{102, 106}, Characters: []byte{0x66, 0x6a}}, + "flat": {Name: "flat", CodePoints: []int{9837}, Characters: []byte{0xe2, 0x99, 0xad}}, + "fllig": {Name: "fllig", CodePoints: []int{64258}, Characters: []byte{0xef, 0xac, 0x82}}, + "fltns": {Name: "fltns", CodePoints: []int{9649}, Characters: []byte{0xe2, 0x96, 0xb1}}, + "fnof": {Name: "fnof", CodePoints: []int{402}, Characters: []byte{0xc6, 0x92}}, + "fopf": {Name: "fopf", CodePoints: []int{120151}, Characters: []byte{0xf0, 0x9d, 0x95, 0x97}}, + "forall": {Name: "forall", CodePoints: []int{8704}, Characters: []byte{0xe2, 0x88, 0x80}}, + "fork": {Name: "fork", CodePoints: []int{8916}, Characters: []byte{0xe2, 0x8b, 0x94}}, + "forkv": {Name: "forkv", CodePoints: []int{10969}, Characters: []byte{0xe2, 0xab, 0x99}}, + "fpartint": {Name: "fpartint", CodePoints: []int{10765}, Characters: []byte{0xe2, 0xa8, 0x8d}}, + "frac12": {Name: "frac12", CodePoints: []int{189}, Characters: []byte{0xc2, 0xbd}}, + "frac13": {Name: "frac13", CodePoints: []int{8531}, Characters: []byte{0xe2, 0x85, 0x93}}, + "frac14": {Name: "frac14", CodePoints: []int{188}, Characters: []byte{0xc2, 0xbc}}, + "frac15": {Name: "frac15", CodePoints: []int{8533}, Characters: []byte{0xe2, 0x85, 0x95}}, + "frac16": {Name: "frac16", CodePoints: []int{8537}, Characters: []byte{0xe2, 0x85, 0x99}}, + "frac18": {Name: "frac18", CodePoints: []int{8539}, Characters: []byte{0xe2, 0x85, 0x9b}}, + "frac23": {Name: "frac23", CodePoints: []int{8532}, Characters: []byte{0xe2, 0x85, 0x94}}, + "frac25": {Name: "frac25", CodePoints: []int{8534}, Characters: []byte{0xe2, 0x85, 0x96}}, + "frac34": {Name: "frac34", CodePoints: []int{190}, Characters: []byte{0xc2, 0xbe}}, + "frac35": {Name: "frac35", CodePoints: []int{8535}, Characters: []byte{0xe2, 0x85, 0x97}}, + "frac38": {Name: "frac38", CodePoints: []int{8540}, Characters: []byte{0xe2, 0x85, 0x9c}}, + "frac45": {Name: "frac45", CodePoints: []int{8536}, Characters: []byte{0xe2, 0x85, 0x98}}, + "frac56": {Name: "frac56", CodePoints: []int{8538}, Characters: []byte{0xe2, 0x85, 0x9a}}, + "frac58": {Name: "frac58", CodePoints: []int{8541}, Characters: []byte{0xe2, 0x85, 0x9d}}, + "frac78": {Name: "frac78", CodePoints: []int{8542}, Characters: []byte{0xe2, 0x85, 0x9e}}, + "frasl": {Name: "frasl", CodePoints: []int{8260}, Characters: []byte{0xe2, 0x81, 0x84}}, + "frown": {Name: "frown", CodePoints: []int{8994}, Characters: []byte{0xe2, 0x8c, 0xa2}}, + "fscr": {Name: "fscr", CodePoints: []int{119995}, Characters: []byte{0xf0, 0x9d, 0x92, 0xbb}}, + "gE": {Name: "gE", CodePoints: []int{8807}, Characters: []byte{0xe2, 0x89, 0xa7}}, + "gEl": {Name: "gEl", CodePoints: []int{10892}, Characters: []byte{0xe2, 0xaa, 0x8c}}, + "gacute": {Name: "gacute", CodePoints: []int{501}, Characters: []byte{0xc7, 0xb5}}, + "gamma": {Name: "gamma", CodePoints: []int{947}, Characters: []byte{0xce, 0xb3}}, + "gammad": {Name: "gammad", CodePoints: []int{989}, Characters: []byte{0xcf, 0x9d}}, + "gap": {Name: "gap", CodePoints: []int{10886}, Characters: []byte{0xe2, 0xaa, 0x86}}, + "gbreve": {Name: "gbreve", CodePoints: []int{287}, Characters: []byte{0xc4, 0x9f}}, + "gcirc": {Name: "gcirc", CodePoints: []int{285}, Characters: []byte{0xc4, 0x9d}}, + "gcy": {Name: "gcy", CodePoints: []int{1075}, Characters: []byte{0xd0, 0xb3}}, + "gdot": {Name: "gdot", CodePoints: []int{289}, Characters: []byte{0xc4, 0xa1}}, + "ge": {Name: "ge", CodePoints: []int{8805}, Characters: []byte{0xe2, 0x89, 0xa5}}, + "gel": {Name: "gel", CodePoints: []int{8923}, Characters: []byte{0xe2, 0x8b, 0x9b}}, + "geq": {Name: "geq", CodePoints: []int{8805}, Characters: []byte{0xe2, 0x89, 0xa5}}, + "geqq": {Name: "geqq", CodePoints: []int{8807}, Characters: []byte{0xe2, 0x89, 0xa7}}, + "geqslant": {Name: "geqslant", CodePoints: []int{10878}, Characters: []byte{0xe2, 0xa9, 0xbe}}, + "ges": {Name: "ges", CodePoints: []int{10878}, Characters: []byte{0xe2, 0xa9, 0xbe}}, + "gescc": {Name: "gescc", CodePoints: []int{10921}, Characters: []byte{0xe2, 0xaa, 0xa9}}, + "gesdot": {Name: "gesdot", CodePoints: []int{10880}, Characters: []byte{0xe2, 0xaa, 0x80}}, + "gesdoto": {Name: "gesdoto", CodePoints: []int{10882}, Characters: []byte{0xe2, 0xaa, 0x82}}, + "gesdotol": {Name: "gesdotol", CodePoints: []int{10884}, Characters: []byte{0xe2, 0xaa, 0x84}}, + "gesl": {Name: "gesl", CodePoints: []int{8923, 65024}, Characters: []byte{0xe2, 0x8b, 0x9b, 0xef, 0xb8, 0x80}}, + "gesles": {Name: "gesles", CodePoints: []int{10900}, Characters: []byte{0xe2, 0xaa, 0x94}}, + "gfr": {Name: "gfr", CodePoints: []int{120100}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa4}}, + "gg": {Name: "gg", CodePoints: []int{8811}, Characters: []byte{0xe2, 0x89, 0xab}}, + "ggg": {Name: "ggg", CodePoints: []int{8921}, Characters: []byte{0xe2, 0x8b, 0x99}}, + "gimel": {Name: "gimel", CodePoints: []int{8503}, Characters: []byte{0xe2, 0x84, 0xb7}}, + "gjcy": {Name: "gjcy", CodePoints: []int{1107}, Characters: []byte{0xd1, 0x93}}, + "gl": {Name: "gl", CodePoints: []int{8823}, Characters: []byte{0xe2, 0x89, 0xb7}}, + "glE": {Name: "glE", CodePoints: []int{10898}, Characters: []byte{0xe2, 0xaa, 0x92}}, + "gla": {Name: "gla", CodePoints: []int{10917}, Characters: []byte{0xe2, 0xaa, 0xa5}}, + "glj": {Name: "glj", CodePoints: []int{10916}, Characters: []byte{0xe2, 0xaa, 0xa4}}, + "gnE": {Name: "gnE", CodePoints: []int{8809}, Characters: []byte{0xe2, 0x89, 0xa9}}, + "gnap": {Name: "gnap", CodePoints: []int{10890}, Characters: []byte{0xe2, 0xaa, 0x8a}}, + "gnapprox": {Name: "gnapprox", CodePoints: []int{10890}, Characters: []byte{0xe2, 0xaa, 0x8a}}, + "gne": {Name: "gne", CodePoints: []int{10888}, Characters: []byte{0xe2, 0xaa, 0x88}}, + "gneq": {Name: "gneq", CodePoints: []int{10888}, Characters: []byte{0xe2, 0xaa, 0x88}}, + "gneqq": {Name: "gneqq", CodePoints: []int{8809}, Characters: []byte{0xe2, 0x89, 0xa9}}, + "gnsim": {Name: "gnsim", CodePoints: []int{8935}, Characters: []byte{0xe2, 0x8b, 0xa7}}, + "gopf": {Name: "gopf", CodePoints: []int{120152}, Characters: []byte{0xf0, 0x9d, 0x95, 0x98}}, + "grave": {Name: "grave", CodePoints: []int{96}, Characters: []byte{0x60}}, + "gscr": {Name: "gscr", CodePoints: []int{8458}, Characters: []byte{0xe2, 0x84, 0x8a}}, + "gsim": {Name: "gsim", CodePoints: []int{8819}, Characters: []byte{0xe2, 0x89, 0xb3}}, + "gsime": {Name: "gsime", CodePoints: []int{10894}, Characters: []byte{0xe2, 0xaa, 0x8e}}, + "gsiml": {Name: "gsiml", CodePoints: []int{10896}, Characters: []byte{0xe2, 0xaa, 0x90}}, + "gt": {Name: "gt", CodePoints: []int{62}, Characters: []byte{0x3e}}, + "gtcc": {Name: "gtcc", CodePoints: []int{10919}, Characters: []byte{0xe2, 0xaa, 0xa7}}, + "gtcir": {Name: "gtcir", CodePoints: []int{10874}, Characters: []byte{0xe2, 0xa9, 0xba}}, + "gtdot": {Name: "gtdot", CodePoints: []int{8919}, Characters: []byte{0xe2, 0x8b, 0x97}}, + "gtlPar": {Name: "gtlPar", CodePoints: []int{10645}, Characters: []byte{0xe2, 0xa6, 0x95}}, + "gtquest": {Name: "gtquest", CodePoints: []int{10876}, Characters: []byte{0xe2, 0xa9, 0xbc}}, + "gtrapprox": {Name: "gtrapprox", CodePoints: []int{10886}, Characters: []byte{0xe2, 0xaa, 0x86}}, + "gtrarr": {Name: "gtrarr", CodePoints: []int{10616}, Characters: []byte{0xe2, 0xa5, 0xb8}}, + "gtrdot": {Name: "gtrdot", CodePoints: []int{8919}, Characters: []byte{0xe2, 0x8b, 0x97}}, + "gtreqless": {Name: "gtreqless", CodePoints: []int{8923}, Characters: []byte{0xe2, 0x8b, 0x9b}}, + "gtreqqless": {Name: "gtreqqless", CodePoints: []int{10892}, Characters: []byte{0xe2, 0xaa, 0x8c}}, + "gtrless": {Name: "gtrless", CodePoints: []int{8823}, Characters: []byte{0xe2, 0x89, 0xb7}}, + "gtrsim": {Name: "gtrsim", CodePoints: []int{8819}, Characters: []byte{0xe2, 0x89, 0xb3}}, + "gvertneqq": {Name: "gvertneqq", CodePoints: []int{8809, 65024}, Characters: []byte{0xe2, 0x89, 0xa9, 0xef, 0xb8, 0x80}}, + "gvnE": {Name: "gvnE", CodePoints: []int{8809, 65024}, Characters: []byte{0xe2, 0x89, 0xa9, 0xef, 0xb8, 0x80}}, + "hArr": {Name: "hArr", CodePoints: []int{8660}, Characters: []byte{0xe2, 0x87, 0x94}}, + "hairsp": {Name: "hairsp", CodePoints: []int{8202}, Characters: []byte{0xe2, 0x80, 0x8a}}, + "half": {Name: "half", CodePoints: []int{189}, Characters: []byte{0xc2, 0xbd}}, + "hamilt": {Name: "hamilt", CodePoints: []int{8459}, Characters: []byte{0xe2, 0x84, 0x8b}}, + "hardcy": {Name: "hardcy", CodePoints: []int{1098}, Characters: []byte{0xd1, 0x8a}}, + "harr": {Name: "harr", CodePoints: []int{8596}, Characters: []byte{0xe2, 0x86, 0x94}}, + "harrcir": {Name: "harrcir", CodePoints: []int{10568}, Characters: []byte{0xe2, 0xa5, 0x88}}, + "harrw": {Name: "harrw", CodePoints: []int{8621}, Characters: []byte{0xe2, 0x86, 0xad}}, + "hbar": {Name: "hbar", CodePoints: []int{8463}, Characters: []byte{0xe2, 0x84, 0x8f}}, + "hcirc": {Name: "hcirc", CodePoints: []int{293}, Characters: []byte{0xc4, 0xa5}}, + "hearts": {Name: "hearts", CodePoints: []int{9829}, Characters: []byte{0xe2, 0x99, 0xa5}}, + "heartsuit": {Name: "heartsuit", CodePoints: []int{9829}, Characters: []byte{0xe2, 0x99, 0xa5}}, + "hellip": {Name: "hellip", CodePoints: []int{8230}, Characters: []byte{0xe2, 0x80, 0xa6}}, + "hercon": {Name: "hercon", CodePoints: []int{8889}, Characters: []byte{0xe2, 0x8a, 0xb9}}, + "hfr": {Name: "hfr", CodePoints: []int{120101}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa5}}, + "hksearow": {Name: "hksearow", CodePoints: []int{10533}, Characters: []byte{0xe2, 0xa4, 0xa5}}, + "hkswarow": {Name: "hkswarow", CodePoints: []int{10534}, Characters: []byte{0xe2, 0xa4, 0xa6}}, + "hoarr": {Name: "hoarr", CodePoints: []int{8703}, Characters: []byte{0xe2, 0x87, 0xbf}}, + "homtht": {Name: "homtht", CodePoints: []int{8763}, Characters: []byte{0xe2, 0x88, 0xbb}}, + "hookleftarrow": {Name: "hookleftarrow", CodePoints: []int{8617}, Characters: []byte{0xe2, 0x86, 0xa9}}, + "hookrightarrow": {Name: "hookrightarrow", CodePoints: []int{8618}, Characters: []byte{0xe2, 0x86, 0xaa}}, + "hopf": {Name: "hopf", CodePoints: []int{120153}, Characters: []byte{0xf0, 0x9d, 0x95, 0x99}}, + "horbar": {Name: "horbar", CodePoints: []int{8213}, Characters: []byte{0xe2, 0x80, 0x95}}, + "hscr": {Name: "hscr", CodePoints: []int{119997}, Characters: []byte{0xf0, 0x9d, 0x92, 0xbd}}, + "hslash": {Name: "hslash", CodePoints: []int{8463}, Characters: []byte{0xe2, 0x84, 0x8f}}, + "hstrok": {Name: "hstrok", CodePoints: []int{295}, Characters: []byte{0xc4, 0xa7}}, + "hybull": {Name: "hybull", CodePoints: []int{8259}, Characters: []byte{0xe2, 0x81, 0x83}}, + "hyphen": {Name: "hyphen", CodePoints: []int{8208}, Characters: []byte{0xe2, 0x80, 0x90}}, + "iacute": {Name: "iacute", CodePoints: []int{237}, Characters: []byte{0xc3, 0xad}}, + "ic": {Name: "ic", CodePoints: []int{8291}, Characters: []byte{0xe2, 0x81, 0xa3}}, + "icirc": {Name: "icirc", CodePoints: []int{238}, Characters: []byte{0xc3, 0xae}}, + "icy": {Name: "icy", CodePoints: []int{1080}, Characters: []byte{0xd0, 0xb8}}, + "iecy": {Name: "iecy", CodePoints: []int{1077}, Characters: []byte{0xd0, 0xb5}}, + "iexcl": {Name: "iexcl", CodePoints: []int{161}, Characters: []byte{0xc2, 0xa1}}, + "iff": {Name: "iff", CodePoints: []int{8660}, Characters: []byte{0xe2, 0x87, 0x94}}, + "ifr": {Name: "ifr", CodePoints: []int{120102}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa6}}, + "igrave": {Name: "igrave", CodePoints: []int{236}, Characters: []byte{0xc3, 0xac}}, + "ii": {Name: "ii", CodePoints: []int{8520}, Characters: []byte{0xe2, 0x85, 0x88}}, + "iiiint": {Name: "iiiint", CodePoints: []int{10764}, Characters: []byte{0xe2, 0xa8, 0x8c}}, + "iiint": {Name: "iiint", CodePoints: []int{8749}, Characters: []byte{0xe2, 0x88, 0xad}}, + "iinfin": {Name: "iinfin", CodePoints: []int{10716}, Characters: []byte{0xe2, 0xa7, 0x9c}}, + "iiota": {Name: "iiota", CodePoints: []int{8489}, Characters: []byte{0xe2, 0x84, 0xa9}}, + "ijlig": {Name: "ijlig", CodePoints: []int{307}, Characters: []byte{0xc4, 0xb3}}, + "imacr": {Name: "imacr", CodePoints: []int{299}, Characters: []byte{0xc4, 0xab}}, + "image": {Name: "image", CodePoints: []int{8465}, Characters: []byte{0xe2, 0x84, 0x91}}, + "imagline": {Name: "imagline", CodePoints: []int{8464}, Characters: []byte{0xe2, 0x84, 0x90}}, + "imagpart": {Name: "imagpart", CodePoints: []int{8465}, Characters: []byte{0xe2, 0x84, 0x91}}, + "imath": {Name: "imath", CodePoints: []int{305}, Characters: []byte{0xc4, 0xb1}}, + "imof": {Name: "imof", CodePoints: []int{8887}, Characters: []byte{0xe2, 0x8a, 0xb7}}, + "imped": {Name: "imped", CodePoints: []int{437}, Characters: []byte{0xc6, 0xb5}}, + "in": {Name: "in", CodePoints: []int{8712}, Characters: []byte{0xe2, 0x88, 0x88}}, + "incare": {Name: "incare", CodePoints: []int{8453}, Characters: []byte{0xe2, 0x84, 0x85}}, + "infin": {Name: "infin", CodePoints: []int{8734}, Characters: []byte{0xe2, 0x88, 0x9e}}, + "infintie": {Name: "infintie", CodePoints: []int{10717}, Characters: []byte{0xe2, 0xa7, 0x9d}}, + "inodot": {Name: "inodot", CodePoints: []int{305}, Characters: []byte{0xc4, 0xb1}}, + "int": {Name: "int", CodePoints: []int{8747}, Characters: []byte{0xe2, 0x88, 0xab}}, + "intcal": {Name: "intcal", CodePoints: []int{8890}, Characters: []byte{0xe2, 0x8a, 0xba}}, + "integers": {Name: "integers", CodePoints: []int{8484}, Characters: []byte{0xe2, 0x84, 0xa4}}, + "intercal": {Name: "intercal", CodePoints: []int{8890}, Characters: []byte{0xe2, 0x8a, 0xba}}, + "intlarhk": {Name: "intlarhk", CodePoints: []int{10775}, Characters: []byte{0xe2, 0xa8, 0x97}}, + "intprod": {Name: "intprod", CodePoints: []int{10812}, Characters: []byte{0xe2, 0xa8, 0xbc}}, + "iocy": {Name: "iocy", CodePoints: []int{1105}, Characters: []byte{0xd1, 0x91}}, + "iogon": {Name: "iogon", CodePoints: []int{303}, Characters: []byte{0xc4, 0xaf}}, + "iopf": {Name: "iopf", CodePoints: []int{120154}, Characters: []byte{0xf0, 0x9d, 0x95, 0x9a}}, + "iota": {Name: "iota", CodePoints: []int{953}, Characters: []byte{0xce, 0xb9}}, + "iprod": {Name: "iprod", CodePoints: []int{10812}, Characters: []byte{0xe2, 0xa8, 0xbc}}, + "iquest": {Name: "iquest", CodePoints: []int{191}, Characters: []byte{0xc2, 0xbf}}, + "iscr": {Name: "iscr", CodePoints: []int{119998}, Characters: []byte{0xf0, 0x9d, 0x92, 0xbe}}, + "isin": {Name: "isin", CodePoints: []int{8712}, Characters: []byte{0xe2, 0x88, 0x88}}, + "isinE": {Name: "isinE", CodePoints: []int{8953}, Characters: []byte{0xe2, 0x8b, 0xb9}}, + "isindot": {Name: "isindot", CodePoints: []int{8949}, Characters: []byte{0xe2, 0x8b, 0xb5}}, + "isins": {Name: "isins", CodePoints: []int{8948}, Characters: []byte{0xe2, 0x8b, 0xb4}}, + "isinsv": {Name: "isinsv", CodePoints: []int{8947}, Characters: []byte{0xe2, 0x8b, 0xb3}}, + "isinv": {Name: "isinv", CodePoints: []int{8712}, Characters: []byte{0xe2, 0x88, 0x88}}, + "it": {Name: "it", CodePoints: []int{8290}, Characters: []byte{0xe2, 0x81, 0xa2}}, + "itilde": {Name: "itilde", CodePoints: []int{297}, Characters: []byte{0xc4, 0xa9}}, + "iukcy": {Name: "iukcy", CodePoints: []int{1110}, Characters: []byte{0xd1, 0x96}}, + "iuml": {Name: "iuml", CodePoints: []int{239}, Characters: []byte{0xc3, 0xaf}}, + "jcirc": {Name: "jcirc", CodePoints: []int{309}, Characters: []byte{0xc4, 0xb5}}, + "jcy": {Name: "jcy", CodePoints: []int{1081}, Characters: []byte{0xd0, 0xb9}}, + "jfr": {Name: "jfr", CodePoints: []int{120103}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa7}}, + "jmath": {Name: "jmath", CodePoints: []int{567}, Characters: []byte{0xc8, 0xb7}}, + "jopf": {Name: "jopf", CodePoints: []int{120155}, Characters: []byte{0xf0, 0x9d, 0x95, 0x9b}}, + "jscr": {Name: "jscr", CodePoints: []int{119999}, Characters: []byte{0xf0, 0x9d, 0x92, 0xbf}}, + "jsercy": {Name: "jsercy", CodePoints: []int{1112}, Characters: []byte{0xd1, 0x98}}, + "jukcy": {Name: "jukcy", CodePoints: []int{1108}, Characters: []byte{0xd1, 0x94}}, + "kappa": {Name: "kappa", CodePoints: []int{954}, Characters: []byte{0xce, 0xba}}, + "kappav": {Name: "kappav", CodePoints: []int{1008}, Characters: []byte{0xcf, 0xb0}}, + "kcedil": {Name: "kcedil", CodePoints: []int{311}, Characters: []byte{0xc4, 0xb7}}, + "kcy": {Name: "kcy", CodePoints: []int{1082}, Characters: []byte{0xd0, 0xba}}, + "kfr": {Name: "kfr", CodePoints: []int{120104}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa8}}, + "kgreen": {Name: "kgreen", CodePoints: []int{312}, Characters: []byte{0xc4, 0xb8}}, + "khcy": {Name: "khcy", CodePoints: []int{1093}, Characters: []byte{0xd1, 0x85}}, + "kjcy": {Name: "kjcy", CodePoints: []int{1116}, Characters: []byte{0xd1, 0x9c}}, + "kopf": {Name: "kopf", CodePoints: []int{120156}, Characters: []byte{0xf0, 0x9d, 0x95, 0x9c}}, + "kscr": {Name: "kscr", CodePoints: []int{120000}, Characters: []byte{0xf0, 0x9d, 0x93, 0x80}}, + "lAarr": {Name: "lAarr", CodePoints: []int{8666}, Characters: []byte{0xe2, 0x87, 0x9a}}, + "lArr": {Name: "lArr", CodePoints: []int{8656}, Characters: []byte{0xe2, 0x87, 0x90}}, + "lAtail": {Name: "lAtail", CodePoints: []int{10523}, Characters: []byte{0xe2, 0xa4, 0x9b}}, + "lBarr": {Name: "lBarr", CodePoints: []int{10510}, Characters: []byte{0xe2, 0xa4, 0x8e}}, + "lE": {Name: "lE", CodePoints: []int{8806}, Characters: []byte{0xe2, 0x89, 0xa6}}, + "lEg": {Name: "lEg", CodePoints: []int{10891}, Characters: []byte{0xe2, 0xaa, 0x8b}}, + "lHar": {Name: "lHar", CodePoints: []int{10594}, Characters: []byte{0xe2, 0xa5, 0xa2}}, + "lacute": {Name: "lacute", CodePoints: []int{314}, Characters: []byte{0xc4, 0xba}}, + "laemptyv": {Name: "laemptyv", CodePoints: []int{10676}, Characters: []byte{0xe2, 0xa6, 0xb4}}, + "lagran": {Name: "lagran", CodePoints: []int{8466}, Characters: []byte{0xe2, 0x84, 0x92}}, + "lambda": {Name: "lambda", CodePoints: []int{955}, Characters: []byte{0xce, 0xbb}}, + "lang": {Name: "lang", CodePoints: []int{10216}, Characters: []byte{0xe2, 0x9f, 0xa8}}, + "langd": {Name: "langd", CodePoints: []int{10641}, Characters: []byte{0xe2, 0xa6, 0x91}}, + "langle": {Name: "langle", CodePoints: []int{10216}, Characters: []byte{0xe2, 0x9f, 0xa8}}, + "lap": {Name: "lap", CodePoints: []int{10885}, Characters: []byte{0xe2, 0xaa, 0x85}}, + "laquo": {Name: "laquo", CodePoints: []int{171}, Characters: []byte{0xc2, 0xab}}, + "larr": {Name: "larr", CodePoints: []int{8592}, Characters: []byte{0xe2, 0x86, 0x90}}, + "larrb": {Name: "larrb", CodePoints: []int{8676}, Characters: []byte{0xe2, 0x87, 0xa4}}, + "larrbfs": {Name: "larrbfs", CodePoints: []int{10527}, Characters: []byte{0xe2, 0xa4, 0x9f}}, + "larrfs": {Name: "larrfs", CodePoints: []int{10525}, Characters: []byte{0xe2, 0xa4, 0x9d}}, + "larrhk": {Name: "larrhk", CodePoints: []int{8617}, Characters: []byte{0xe2, 0x86, 0xa9}}, + "larrlp": {Name: "larrlp", CodePoints: []int{8619}, Characters: []byte{0xe2, 0x86, 0xab}}, + "larrpl": {Name: "larrpl", CodePoints: []int{10553}, Characters: []byte{0xe2, 0xa4, 0xb9}}, + "larrsim": {Name: "larrsim", CodePoints: []int{10611}, Characters: []byte{0xe2, 0xa5, 0xb3}}, + "larrtl": {Name: "larrtl", CodePoints: []int{8610}, Characters: []byte{0xe2, 0x86, 0xa2}}, + "lat": {Name: "lat", CodePoints: []int{10923}, Characters: []byte{0xe2, 0xaa, 0xab}}, + "latail": {Name: "latail", CodePoints: []int{10521}, Characters: []byte{0xe2, 0xa4, 0x99}}, + "late": {Name: "late", CodePoints: []int{10925}, Characters: []byte{0xe2, 0xaa, 0xad}}, + "lates": {Name: "lates", CodePoints: []int{10925, 65024}, Characters: []byte{0xe2, 0xaa, 0xad, 0xef, 0xb8, 0x80}}, + "lbarr": {Name: "lbarr", CodePoints: []int{10508}, Characters: []byte{0xe2, 0xa4, 0x8c}}, + "lbbrk": {Name: "lbbrk", CodePoints: []int{10098}, Characters: []byte{0xe2, 0x9d, 0xb2}}, + "lbrace": {Name: "lbrace", CodePoints: []int{123}, Characters: []byte{0x7b}}, + "lbrack": {Name: "lbrack", CodePoints: []int{91}, Characters: []byte{0x5b}}, + "lbrke": {Name: "lbrke", CodePoints: []int{10635}, Characters: []byte{0xe2, 0xa6, 0x8b}}, + "lbrksld": {Name: "lbrksld", CodePoints: []int{10639}, Characters: []byte{0xe2, 0xa6, 0x8f}}, + "lbrkslu": {Name: "lbrkslu", CodePoints: []int{10637}, Characters: []byte{0xe2, 0xa6, 0x8d}}, + "lcaron": {Name: "lcaron", CodePoints: []int{318}, Characters: []byte{0xc4, 0xbe}}, + "lcedil": {Name: "lcedil", CodePoints: []int{316}, Characters: []byte{0xc4, 0xbc}}, + "lceil": {Name: "lceil", CodePoints: []int{8968}, Characters: []byte{0xe2, 0x8c, 0x88}}, + "lcub": {Name: "lcub", CodePoints: []int{123}, Characters: []byte{0x7b}}, + "lcy": {Name: "lcy", CodePoints: []int{1083}, Characters: []byte{0xd0, 0xbb}}, + "ldca": {Name: "ldca", CodePoints: []int{10550}, Characters: []byte{0xe2, 0xa4, 0xb6}}, + "ldquo": {Name: "ldquo", CodePoints: []int{8220}, Characters: []byte{0xe2, 0x80, 0x9c}}, + "ldquor": {Name: "ldquor", CodePoints: []int{8222}, Characters: []byte{0xe2, 0x80, 0x9e}}, + "ldrdhar": {Name: "ldrdhar", CodePoints: []int{10599}, Characters: []byte{0xe2, 0xa5, 0xa7}}, + "ldrushar": {Name: "ldrushar", CodePoints: []int{10571}, Characters: []byte{0xe2, 0xa5, 0x8b}}, + "ldsh": {Name: "ldsh", CodePoints: []int{8626}, Characters: []byte{0xe2, 0x86, 0xb2}}, + "le": {Name: "le", CodePoints: []int{8804}, Characters: []byte{0xe2, 0x89, 0xa4}}, + "leftarrow": {Name: "leftarrow", CodePoints: []int{8592}, Characters: []byte{0xe2, 0x86, 0x90}}, + "leftarrowtail": {Name: "leftarrowtail", CodePoints: []int{8610}, Characters: []byte{0xe2, 0x86, 0xa2}}, + "leftharpoondown": {Name: "leftharpoondown", CodePoints: []int{8637}, Characters: []byte{0xe2, 0x86, 0xbd}}, + "leftharpoonup": {Name: "leftharpoonup", CodePoints: []int{8636}, Characters: []byte{0xe2, 0x86, 0xbc}}, + "leftleftarrows": {Name: "leftleftarrows", CodePoints: []int{8647}, Characters: []byte{0xe2, 0x87, 0x87}}, + "leftrightarrow": {Name: "leftrightarrow", CodePoints: []int{8596}, Characters: []byte{0xe2, 0x86, 0x94}}, + "leftrightarrows": {Name: "leftrightarrows", CodePoints: []int{8646}, Characters: []byte{0xe2, 0x87, 0x86}}, + "leftrightharpoons": {Name: "leftrightharpoons", CodePoints: []int{8651}, Characters: []byte{0xe2, 0x87, 0x8b}}, + "leftrightsquigarrow": {Name: "leftrightsquigarrow", CodePoints: []int{8621}, Characters: []byte{0xe2, 0x86, 0xad}}, + "leftthreetimes": {Name: "leftthreetimes", CodePoints: []int{8907}, Characters: []byte{0xe2, 0x8b, 0x8b}}, + "leg": {Name: "leg", CodePoints: []int{8922}, Characters: []byte{0xe2, 0x8b, 0x9a}}, + "leq": {Name: "leq", CodePoints: []int{8804}, Characters: []byte{0xe2, 0x89, 0xa4}}, + "leqq": {Name: "leqq", CodePoints: []int{8806}, Characters: []byte{0xe2, 0x89, 0xa6}}, + "leqslant": {Name: "leqslant", CodePoints: []int{10877}, Characters: []byte{0xe2, 0xa9, 0xbd}}, + "les": {Name: "les", CodePoints: []int{10877}, Characters: []byte{0xe2, 0xa9, 0xbd}}, + "lescc": {Name: "lescc", CodePoints: []int{10920}, Characters: []byte{0xe2, 0xaa, 0xa8}}, + "lesdot": {Name: "lesdot", CodePoints: []int{10879}, Characters: []byte{0xe2, 0xa9, 0xbf}}, + "lesdoto": {Name: "lesdoto", CodePoints: []int{10881}, Characters: []byte{0xe2, 0xaa, 0x81}}, + "lesdotor": {Name: "lesdotor", CodePoints: []int{10883}, Characters: []byte{0xe2, 0xaa, 0x83}}, + "lesg": {Name: "lesg", CodePoints: []int{8922, 65024}, Characters: []byte{0xe2, 0x8b, 0x9a, 0xef, 0xb8, 0x80}}, + "lesges": {Name: "lesges", CodePoints: []int{10899}, Characters: []byte{0xe2, 0xaa, 0x93}}, + "lessapprox": {Name: "lessapprox", CodePoints: []int{10885}, Characters: []byte{0xe2, 0xaa, 0x85}}, + "lessdot": {Name: "lessdot", CodePoints: []int{8918}, Characters: []byte{0xe2, 0x8b, 0x96}}, + "lesseqgtr": {Name: "lesseqgtr", CodePoints: []int{8922}, Characters: []byte{0xe2, 0x8b, 0x9a}}, + "lesseqqgtr": {Name: "lesseqqgtr", CodePoints: []int{10891}, Characters: []byte{0xe2, 0xaa, 0x8b}}, + "lessgtr": {Name: "lessgtr", CodePoints: []int{8822}, Characters: []byte{0xe2, 0x89, 0xb6}}, + "lesssim": {Name: "lesssim", CodePoints: []int{8818}, Characters: []byte{0xe2, 0x89, 0xb2}}, + "lfisht": {Name: "lfisht", CodePoints: []int{10620}, Characters: []byte{0xe2, 0xa5, 0xbc}}, + "lfloor": {Name: "lfloor", CodePoints: []int{8970}, Characters: []byte{0xe2, 0x8c, 0x8a}}, + "lfr": {Name: "lfr", CodePoints: []int{120105}, Characters: []byte{0xf0, 0x9d, 0x94, 0xa9}}, + "lg": {Name: "lg", CodePoints: []int{8822}, Characters: []byte{0xe2, 0x89, 0xb6}}, + "lgE": {Name: "lgE", CodePoints: []int{10897}, Characters: []byte{0xe2, 0xaa, 0x91}}, + "lhard": {Name: "lhard", CodePoints: []int{8637}, Characters: []byte{0xe2, 0x86, 0xbd}}, + "lharu": {Name: "lharu", CodePoints: []int{8636}, Characters: []byte{0xe2, 0x86, 0xbc}}, + "lharul": {Name: "lharul", CodePoints: []int{10602}, Characters: []byte{0xe2, 0xa5, 0xaa}}, + "lhblk": {Name: "lhblk", CodePoints: []int{9604}, Characters: []byte{0xe2, 0x96, 0x84}}, + "ljcy": {Name: "ljcy", CodePoints: []int{1113}, Characters: []byte{0xd1, 0x99}}, + "ll": {Name: "ll", CodePoints: []int{8810}, Characters: []byte{0xe2, 0x89, 0xaa}}, + "llarr": {Name: "llarr", CodePoints: []int{8647}, Characters: []byte{0xe2, 0x87, 0x87}}, + "llcorner": {Name: "llcorner", CodePoints: []int{8990}, Characters: []byte{0xe2, 0x8c, 0x9e}}, + "llhard": {Name: "llhard", CodePoints: []int{10603}, Characters: []byte{0xe2, 0xa5, 0xab}}, + "lltri": {Name: "lltri", CodePoints: []int{9722}, Characters: []byte{0xe2, 0x97, 0xba}}, + "lmidot": {Name: "lmidot", CodePoints: []int{320}, Characters: []byte{0xc5, 0x80}}, + "lmoust": {Name: "lmoust", CodePoints: []int{9136}, Characters: []byte{0xe2, 0x8e, 0xb0}}, + "lmoustache": {Name: "lmoustache", CodePoints: []int{9136}, Characters: []byte{0xe2, 0x8e, 0xb0}}, + "lnE": {Name: "lnE", CodePoints: []int{8808}, Characters: []byte{0xe2, 0x89, 0xa8}}, + "lnap": {Name: "lnap", CodePoints: []int{10889}, Characters: []byte{0xe2, 0xaa, 0x89}}, + "lnapprox": {Name: "lnapprox", CodePoints: []int{10889}, Characters: []byte{0xe2, 0xaa, 0x89}}, + "lne": {Name: "lne", CodePoints: []int{10887}, Characters: []byte{0xe2, 0xaa, 0x87}}, + "lneq": {Name: "lneq", CodePoints: []int{10887}, Characters: []byte{0xe2, 0xaa, 0x87}}, + "lneqq": {Name: "lneqq", CodePoints: []int{8808}, Characters: []byte{0xe2, 0x89, 0xa8}}, + "lnsim": {Name: "lnsim", CodePoints: []int{8934}, Characters: []byte{0xe2, 0x8b, 0xa6}}, + "loang": {Name: "loang", CodePoints: []int{10220}, Characters: []byte{0xe2, 0x9f, 0xac}}, + "loarr": {Name: "loarr", CodePoints: []int{8701}, Characters: []byte{0xe2, 0x87, 0xbd}}, + "lobrk": {Name: "lobrk", CodePoints: []int{10214}, Characters: []byte{0xe2, 0x9f, 0xa6}}, + "longleftarrow": {Name: "longleftarrow", CodePoints: []int{10229}, Characters: []byte{0xe2, 0x9f, 0xb5}}, + "longleftrightarrow": {Name: "longleftrightarrow", CodePoints: []int{10231}, Characters: []byte{0xe2, 0x9f, 0xb7}}, + "longmapsto": {Name: "longmapsto", CodePoints: []int{10236}, Characters: []byte{0xe2, 0x9f, 0xbc}}, + "longrightarrow": {Name: "longrightarrow", CodePoints: []int{10230}, Characters: []byte{0xe2, 0x9f, 0xb6}}, + "looparrowleft": {Name: "looparrowleft", CodePoints: []int{8619}, Characters: []byte{0xe2, 0x86, 0xab}}, + "looparrowright": {Name: "looparrowright", CodePoints: []int{8620}, Characters: []byte{0xe2, 0x86, 0xac}}, + "lopar": {Name: "lopar", CodePoints: []int{10629}, Characters: []byte{0xe2, 0xa6, 0x85}}, + "lopf": {Name: "lopf", CodePoints: []int{120157}, Characters: []byte{0xf0, 0x9d, 0x95, 0x9d}}, + "loplus": {Name: "loplus", CodePoints: []int{10797}, Characters: []byte{0xe2, 0xa8, 0xad}}, + "lotimes": {Name: "lotimes", CodePoints: []int{10804}, Characters: []byte{0xe2, 0xa8, 0xb4}}, + "lowast": {Name: "lowast", CodePoints: []int{8727}, Characters: []byte{0xe2, 0x88, 0x97}}, + "lowbar": {Name: "lowbar", CodePoints: []int{95}, Characters: []byte{0x5f}}, + "loz": {Name: "loz", CodePoints: []int{9674}, Characters: []byte{0xe2, 0x97, 0x8a}}, + "lozenge": {Name: "lozenge", CodePoints: []int{9674}, Characters: []byte{0xe2, 0x97, 0x8a}}, + "lozf": {Name: "lozf", CodePoints: []int{10731}, Characters: []byte{0xe2, 0xa7, 0xab}}, + "lpar": {Name: "lpar", CodePoints: []int{40}, Characters: []byte{0x28}}, + "lparlt": {Name: "lparlt", CodePoints: []int{10643}, Characters: []byte{0xe2, 0xa6, 0x93}}, + "lrarr": {Name: "lrarr", CodePoints: []int{8646}, Characters: []byte{0xe2, 0x87, 0x86}}, + "lrcorner": {Name: "lrcorner", CodePoints: []int{8991}, Characters: []byte{0xe2, 0x8c, 0x9f}}, + "lrhar": {Name: "lrhar", CodePoints: []int{8651}, Characters: []byte{0xe2, 0x87, 0x8b}}, + "lrhard": {Name: "lrhard", CodePoints: []int{10605}, Characters: []byte{0xe2, 0xa5, 0xad}}, + "lrm": {Name: "lrm", CodePoints: []int{8206}, Characters: []byte{0xe2, 0x80, 0x8e}}, + "lrtri": {Name: "lrtri", CodePoints: []int{8895}, Characters: []byte{0xe2, 0x8a, 0xbf}}, + "lsaquo": {Name: "lsaquo", CodePoints: []int{8249}, Characters: []byte{0xe2, 0x80, 0xb9}}, + "lscr": {Name: "lscr", CodePoints: []int{120001}, Characters: []byte{0xf0, 0x9d, 0x93, 0x81}}, + "lsh": {Name: "lsh", CodePoints: []int{8624}, Characters: []byte{0xe2, 0x86, 0xb0}}, + "lsim": {Name: "lsim", CodePoints: []int{8818}, Characters: []byte{0xe2, 0x89, 0xb2}}, + "lsime": {Name: "lsime", CodePoints: []int{10893}, Characters: []byte{0xe2, 0xaa, 0x8d}}, + "lsimg": {Name: "lsimg", CodePoints: []int{10895}, Characters: []byte{0xe2, 0xaa, 0x8f}}, + "lsqb": {Name: "lsqb", CodePoints: []int{91}, Characters: []byte{0x5b}}, + "lsquo": {Name: "lsquo", CodePoints: []int{8216}, Characters: []byte{0xe2, 0x80, 0x98}}, + "lsquor": {Name: "lsquor", CodePoints: []int{8218}, Characters: []byte{0xe2, 0x80, 0x9a}}, + "lstrok": {Name: "lstrok", CodePoints: []int{322}, Characters: []byte{0xc5, 0x82}}, + "lt": {Name: "lt", CodePoints: []int{60}, Characters: []byte{0x3c}}, + "ltcc": {Name: "ltcc", CodePoints: []int{10918}, Characters: []byte{0xe2, 0xaa, 0xa6}}, + "ltcir": {Name: "ltcir", CodePoints: []int{10873}, Characters: []byte{0xe2, 0xa9, 0xb9}}, + "ltdot": {Name: "ltdot", CodePoints: []int{8918}, Characters: []byte{0xe2, 0x8b, 0x96}}, + "lthree": {Name: "lthree", CodePoints: []int{8907}, Characters: []byte{0xe2, 0x8b, 0x8b}}, + "ltimes": {Name: "ltimes", CodePoints: []int{8905}, Characters: []byte{0xe2, 0x8b, 0x89}}, + "ltlarr": {Name: "ltlarr", CodePoints: []int{10614}, Characters: []byte{0xe2, 0xa5, 0xb6}}, + "ltquest": {Name: "ltquest", CodePoints: []int{10875}, Characters: []byte{0xe2, 0xa9, 0xbb}}, + "ltrPar": {Name: "ltrPar", CodePoints: []int{10646}, Characters: []byte{0xe2, 0xa6, 0x96}}, + "ltri": {Name: "ltri", CodePoints: []int{9667}, Characters: []byte{0xe2, 0x97, 0x83}}, + "ltrie": {Name: "ltrie", CodePoints: []int{8884}, Characters: []byte{0xe2, 0x8a, 0xb4}}, + "ltrif": {Name: "ltrif", CodePoints: []int{9666}, Characters: []byte{0xe2, 0x97, 0x82}}, + "lurdshar": {Name: "lurdshar", CodePoints: []int{10570}, Characters: []byte{0xe2, 0xa5, 0x8a}}, + "luruhar": {Name: "luruhar", CodePoints: []int{10598}, Characters: []byte{0xe2, 0xa5, 0xa6}}, + "lvertneqq": {Name: "lvertneqq", CodePoints: []int{8808, 65024}, Characters: []byte{0xe2, 0x89, 0xa8, 0xef, 0xb8, 0x80}}, + "lvnE": {Name: "lvnE", CodePoints: []int{8808, 65024}, Characters: []byte{0xe2, 0x89, 0xa8, 0xef, 0xb8, 0x80}}, + "mDDot": {Name: "mDDot", CodePoints: []int{8762}, Characters: []byte{0xe2, 0x88, 0xba}}, + "macr": {Name: "macr", CodePoints: []int{175}, Characters: []byte{0xc2, 0xaf}}, + "male": {Name: "male", CodePoints: []int{9794}, Characters: []byte{0xe2, 0x99, 0x82}}, + "malt": {Name: "malt", CodePoints: []int{10016}, Characters: []byte{0xe2, 0x9c, 0xa0}}, + "maltese": {Name: "maltese", CodePoints: []int{10016}, Characters: []byte{0xe2, 0x9c, 0xa0}}, + "map": {Name: "map", CodePoints: []int{8614}, Characters: []byte{0xe2, 0x86, 0xa6}}, + "mapsto": {Name: "mapsto", CodePoints: []int{8614}, Characters: []byte{0xe2, 0x86, 0xa6}}, + "mapstodown": {Name: "mapstodown", CodePoints: []int{8615}, Characters: []byte{0xe2, 0x86, 0xa7}}, + "mapstoleft": {Name: "mapstoleft", CodePoints: []int{8612}, Characters: []byte{0xe2, 0x86, 0xa4}}, + "mapstoup": {Name: "mapstoup", CodePoints: []int{8613}, Characters: []byte{0xe2, 0x86, 0xa5}}, + "marker": {Name: "marker", CodePoints: []int{9646}, Characters: []byte{0xe2, 0x96, 0xae}}, + "mcomma": {Name: "mcomma", CodePoints: []int{10793}, Characters: []byte{0xe2, 0xa8, 0xa9}}, + "mcy": {Name: "mcy", CodePoints: []int{1084}, Characters: []byte{0xd0, 0xbc}}, + "mdash": {Name: "mdash", CodePoints: []int{8212}, Characters: []byte{0xe2, 0x80, 0x94}}, + "measuredangle": {Name: "measuredangle", CodePoints: []int{8737}, Characters: []byte{0xe2, 0x88, 0xa1}}, + "mfr": {Name: "mfr", CodePoints: []int{120106}, Characters: []byte{0xf0, 0x9d, 0x94, 0xaa}}, + "mho": {Name: "mho", CodePoints: []int{8487}, Characters: []byte{0xe2, 0x84, 0xa7}}, + "micro": {Name: "micro", CodePoints: []int{181}, Characters: []byte{0xc2, 0xb5}}, + "mid": {Name: "mid", CodePoints: []int{8739}, Characters: []byte{0xe2, 0x88, 0xa3}}, + "midast": {Name: "midast", CodePoints: []int{42}, Characters: []byte{0x2a}}, + "midcir": {Name: "midcir", CodePoints: []int{10992}, Characters: []byte{0xe2, 0xab, 0xb0}}, + "middot": {Name: "middot", CodePoints: []int{183}, Characters: []byte{0xc2, 0xb7}}, + "minus": {Name: "minus", CodePoints: []int{8722}, Characters: []byte{0xe2, 0x88, 0x92}}, + "minusb": {Name: "minusb", CodePoints: []int{8863}, Characters: []byte{0xe2, 0x8a, 0x9f}}, + "minusd": {Name: "minusd", CodePoints: []int{8760}, Characters: []byte{0xe2, 0x88, 0xb8}}, + "minusdu": {Name: "minusdu", CodePoints: []int{10794}, Characters: []byte{0xe2, 0xa8, 0xaa}}, + "mlcp": {Name: "mlcp", CodePoints: []int{10971}, Characters: []byte{0xe2, 0xab, 0x9b}}, + "mldr": {Name: "mldr", CodePoints: []int{8230}, Characters: []byte{0xe2, 0x80, 0xa6}}, + "mnplus": {Name: "mnplus", CodePoints: []int{8723}, Characters: []byte{0xe2, 0x88, 0x93}}, + "models": {Name: "models", CodePoints: []int{8871}, Characters: []byte{0xe2, 0x8a, 0xa7}}, + "mopf": {Name: "mopf", CodePoints: []int{120158}, Characters: []byte{0xf0, 0x9d, 0x95, 0x9e}}, + "mp": {Name: "mp", CodePoints: []int{8723}, Characters: []byte{0xe2, 0x88, 0x93}}, + "mscr": {Name: "mscr", CodePoints: []int{120002}, Characters: []byte{0xf0, 0x9d, 0x93, 0x82}}, + "mstpos": {Name: "mstpos", CodePoints: []int{8766}, Characters: []byte{0xe2, 0x88, 0xbe}}, + "mu": {Name: "mu", CodePoints: []int{956}, Characters: []byte{0xce, 0xbc}}, + "multimap": {Name: "multimap", CodePoints: []int{8888}, Characters: []byte{0xe2, 0x8a, 0xb8}}, + "mumap": {Name: "mumap", CodePoints: []int{8888}, Characters: []byte{0xe2, 0x8a, 0xb8}}, + "nGg": {Name: "nGg", CodePoints: []int{8921, 824}, Characters: []byte{0xe2, 0x8b, 0x99, 0xcc, 0xb8}}, + "nGt": {Name: "nGt", CodePoints: []int{8811, 8402}, Characters: []byte{0xe2, 0x89, 0xab, 0xe2, 0x83, 0x92}}, + "nGtv": {Name: "nGtv", CodePoints: []int{8811, 824}, Characters: []byte{0xe2, 0x89, 0xab, 0xcc, 0xb8}}, + "nLeftarrow": {Name: "nLeftarrow", CodePoints: []int{8653}, Characters: []byte{0xe2, 0x87, 0x8d}}, + "nLeftrightarrow": {Name: "nLeftrightarrow", CodePoints: []int{8654}, Characters: []byte{0xe2, 0x87, 0x8e}}, + "nLl": {Name: "nLl", CodePoints: []int{8920, 824}, Characters: []byte{0xe2, 0x8b, 0x98, 0xcc, 0xb8}}, + "nLt": {Name: "nLt", CodePoints: []int{8810, 8402}, Characters: []byte{0xe2, 0x89, 0xaa, 0xe2, 0x83, 0x92}}, + "nLtv": {Name: "nLtv", CodePoints: []int{8810, 824}, Characters: []byte{0xe2, 0x89, 0xaa, 0xcc, 0xb8}}, + "nRightarrow": {Name: "nRightarrow", CodePoints: []int{8655}, Characters: []byte{0xe2, 0x87, 0x8f}}, + "nVDash": {Name: "nVDash", CodePoints: []int{8879}, Characters: []byte{0xe2, 0x8a, 0xaf}}, + "nVdash": {Name: "nVdash", CodePoints: []int{8878}, Characters: []byte{0xe2, 0x8a, 0xae}}, + "nabla": {Name: "nabla", CodePoints: []int{8711}, Characters: []byte{0xe2, 0x88, 0x87}}, + "nacute": {Name: "nacute", CodePoints: []int{324}, Characters: []byte{0xc5, 0x84}}, + "nang": {Name: "nang", CodePoints: []int{8736, 8402}, Characters: []byte{0xe2, 0x88, 0xa0, 0xe2, 0x83, 0x92}}, + "nap": {Name: "nap", CodePoints: []int{8777}, Characters: []byte{0xe2, 0x89, 0x89}}, + "napE": {Name: "napE", CodePoints: []int{10864, 824}, Characters: []byte{0xe2, 0xa9, 0xb0, 0xcc, 0xb8}}, + "napid": {Name: "napid", CodePoints: []int{8779, 824}, Characters: []byte{0xe2, 0x89, 0x8b, 0xcc, 0xb8}}, + "napos": {Name: "napos", CodePoints: []int{329}, Characters: []byte{0xc5, 0x89}}, + "napprox": {Name: "napprox", CodePoints: []int{8777}, Characters: []byte{0xe2, 0x89, 0x89}}, + "natur": {Name: "natur", CodePoints: []int{9838}, Characters: []byte{0xe2, 0x99, 0xae}}, + "natural": {Name: "natural", CodePoints: []int{9838}, Characters: []byte{0xe2, 0x99, 0xae}}, + "naturals": {Name: "naturals", CodePoints: []int{8469}, Characters: []byte{0xe2, 0x84, 0x95}}, + "nbsp": {Name: "nbsp", CodePoints: []int{160}, Characters: []byte{0xc2, 0xa0}}, + "nbump": {Name: "nbump", CodePoints: []int{8782, 824}, Characters: []byte{0xe2, 0x89, 0x8e, 0xcc, 0xb8}}, + "nbumpe": {Name: "nbumpe", CodePoints: []int{8783, 824}, Characters: []byte{0xe2, 0x89, 0x8f, 0xcc, 0xb8}}, + "ncap": {Name: "ncap", CodePoints: []int{10819}, Characters: []byte{0xe2, 0xa9, 0x83}}, + "ncaron": {Name: "ncaron", CodePoints: []int{328}, Characters: []byte{0xc5, 0x88}}, + "ncedil": {Name: "ncedil", CodePoints: []int{326}, Characters: []byte{0xc5, 0x86}}, + "ncong": {Name: "ncong", CodePoints: []int{8775}, Characters: []byte{0xe2, 0x89, 0x87}}, + "ncongdot": {Name: "ncongdot", CodePoints: []int{10861, 824}, Characters: []byte{0xe2, 0xa9, 0xad, 0xcc, 0xb8}}, + "ncup": {Name: "ncup", CodePoints: []int{10818}, Characters: []byte{0xe2, 0xa9, 0x82}}, + "ncy": {Name: "ncy", CodePoints: []int{1085}, Characters: []byte{0xd0, 0xbd}}, + "ndash": {Name: "ndash", CodePoints: []int{8211}, Characters: []byte{0xe2, 0x80, 0x93}}, + "ne": {Name: "ne", CodePoints: []int{8800}, Characters: []byte{0xe2, 0x89, 0xa0}}, + "neArr": {Name: "neArr", CodePoints: []int{8663}, Characters: []byte{0xe2, 0x87, 0x97}}, + "nearhk": {Name: "nearhk", CodePoints: []int{10532}, Characters: []byte{0xe2, 0xa4, 0xa4}}, + "nearr": {Name: "nearr", CodePoints: []int{8599}, Characters: []byte{0xe2, 0x86, 0x97}}, + "nearrow": {Name: "nearrow", CodePoints: []int{8599}, Characters: []byte{0xe2, 0x86, 0x97}}, + "nedot": {Name: "nedot", CodePoints: []int{8784, 824}, Characters: []byte{0xe2, 0x89, 0x90, 0xcc, 0xb8}}, + "nequiv": {Name: "nequiv", CodePoints: []int{8802}, Characters: []byte{0xe2, 0x89, 0xa2}}, + "nesear": {Name: "nesear", CodePoints: []int{10536}, Characters: []byte{0xe2, 0xa4, 0xa8}}, + "nesim": {Name: "nesim", CodePoints: []int{8770, 824}, Characters: []byte{0xe2, 0x89, 0x82, 0xcc, 0xb8}}, + "nexist": {Name: "nexist", CodePoints: []int{8708}, Characters: []byte{0xe2, 0x88, 0x84}}, + "nexists": {Name: "nexists", CodePoints: []int{8708}, Characters: []byte{0xe2, 0x88, 0x84}}, + "nfr": {Name: "nfr", CodePoints: []int{120107}, Characters: []byte{0xf0, 0x9d, 0x94, 0xab}}, + "ngE": {Name: "ngE", CodePoints: []int{8807, 824}, Characters: []byte{0xe2, 0x89, 0xa7, 0xcc, 0xb8}}, + "nge": {Name: "nge", CodePoints: []int{8817}, Characters: []byte{0xe2, 0x89, 0xb1}}, + "ngeq": {Name: "ngeq", CodePoints: []int{8817}, Characters: []byte{0xe2, 0x89, 0xb1}}, + "ngeqq": {Name: "ngeqq", CodePoints: []int{8807, 824}, Characters: []byte{0xe2, 0x89, 0xa7, 0xcc, 0xb8}}, + "ngeqslant": {Name: "ngeqslant", CodePoints: []int{10878, 824}, Characters: []byte{0xe2, 0xa9, 0xbe, 0xcc, 0xb8}}, + "nges": {Name: "nges", CodePoints: []int{10878, 824}, Characters: []byte{0xe2, 0xa9, 0xbe, 0xcc, 0xb8}}, + "ngsim": {Name: "ngsim", CodePoints: []int{8821}, Characters: []byte{0xe2, 0x89, 0xb5}}, + "ngt": {Name: "ngt", CodePoints: []int{8815}, Characters: []byte{0xe2, 0x89, 0xaf}}, + "ngtr": {Name: "ngtr", CodePoints: []int{8815}, Characters: []byte{0xe2, 0x89, 0xaf}}, + "nhArr": {Name: "nhArr", CodePoints: []int{8654}, Characters: []byte{0xe2, 0x87, 0x8e}}, + "nharr": {Name: "nharr", CodePoints: []int{8622}, Characters: []byte{0xe2, 0x86, 0xae}}, + "nhpar": {Name: "nhpar", CodePoints: []int{10994}, Characters: []byte{0xe2, 0xab, 0xb2}}, + "ni": {Name: "ni", CodePoints: []int{8715}, Characters: []byte{0xe2, 0x88, 0x8b}}, + "nis": {Name: "nis", CodePoints: []int{8956}, Characters: []byte{0xe2, 0x8b, 0xbc}}, + "nisd": {Name: "nisd", CodePoints: []int{8954}, Characters: []byte{0xe2, 0x8b, 0xba}}, + "niv": {Name: "niv", CodePoints: []int{8715}, Characters: []byte{0xe2, 0x88, 0x8b}}, + "njcy": {Name: "njcy", CodePoints: []int{1114}, Characters: []byte{0xd1, 0x9a}}, + "nlArr": {Name: "nlArr", CodePoints: []int{8653}, Characters: []byte{0xe2, 0x87, 0x8d}}, + "nlE": {Name: "nlE", CodePoints: []int{8806, 824}, Characters: []byte{0xe2, 0x89, 0xa6, 0xcc, 0xb8}}, + "nlarr": {Name: "nlarr", CodePoints: []int{8602}, Characters: []byte{0xe2, 0x86, 0x9a}}, + "nldr": {Name: "nldr", CodePoints: []int{8229}, Characters: []byte{0xe2, 0x80, 0xa5}}, + "nle": {Name: "nle", CodePoints: []int{8816}, Characters: []byte{0xe2, 0x89, 0xb0}}, + "nleftarrow": {Name: "nleftarrow", CodePoints: []int{8602}, Characters: []byte{0xe2, 0x86, 0x9a}}, + "nleftrightarrow": {Name: "nleftrightarrow", CodePoints: []int{8622}, Characters: []byte{0xe2, 0x86, 0xae}}, + "nleq": {Name: "nleq", CodePoints: []int{8816}, Characters: []byte{0xe2, 0x89, 0xb0}}, + "nleqq": {Name: "nleqq", CodePoints: []int{8806, 824}, Characters: []byte{0xe2, 0x89, 0xa6, 0xcc, 0xb8}}, + "nleqslant": {Name: "nleqslant", CodePoints: []int{10877, 824}, Characters: []byte{0xe2, 0xa9, 0xbd, 0xcc, 0xb8}}, + "nles": {Name: "nles", CodePoints: []int{10877, 824}, Characters: []byte{0xe2, 0xa9, 0xbd, 0xcc, 0xb8}}, + "nless": {Name: "nless", CodePoints: []int{8814}, Characters: []byte{0xe2, 0x89, 0xae}}, + "nlsim": {Name: "nlsim", CodePoints: []int{8820}, Characters: []byte{0xe2, 0x89, 0xb4}}, + "nlt": {Name: "nlt", CodePoints: []int{8814}, Characters: []byte{0xe2, 0x89, 0xae}}, + "nltri": {Name: "nltri", CodePoints: []int{8938}, Characters: []byte{0xe2, 0x8b, 0xaa}}, + "nltrie": {Name: "nltrie", CodePoints: []int{8940}, Characters: []byte{0xe2, 0x8b, 0xac}}, + "nmid": {Name: "nmid", CodePoints: []int{8740}, Characters: []byte{0xe2, 0x88, 0xa4}}, + "nopf": {Name: "nopf", CodePoints: []int{120159}, Characters: []byte{0xf0, 0x9d, 0x95, 0x9f}}, + "not": {Name: "not", CodePoints: []int{172}, Characters: []byte{0xc2, 0xac}}, + "notin": {Name: "notin", CodePoints: []int{8713}, Characters: []byte{0xe2, 0x88, 0x89}}, + "notinE": {Name: "notinE", CodePoints: []int{8953, 824}, Characters: []byte{0xe2, 0x8b, 0xb9, 0xcc, 0xb8}}, + "notindot": {Name: "notindot", CodePoints: []int{8949, 824}, Characters: []byte{0xe2, 0x8b, 0xb5, 0xcc, 0xb8}}, + "notinva": {Name: "notinva", CodePoints: []int{8713}, Characters: []byte{0xe2, 0x88, 0x89}}, + "notinvb": {Name: "notinvb", CodePoints: []int{8951}, Characters: []byte{0xe2, 0x8b, 0xb7}}, + "notinvc": {Name: "notinvc", CodePoints: []int{8950}, Characters: []byte{0xe2, 0x8b, 0xb6}}, + "notni": {Name: "notni", CodePoints: []int{8716}, Characters: []byte{0xe2, 0x88, 0x8c}}, + "notniva": {Name: "notniva", CodePoints: []int{8716}, Characters: []byte{0xe2, 0x88, 0x8c}}, + "notnivb": {Name: "notnivb", CodePoints: []int{8958}, Characters: []byte{0xe2, 0x8b, 0xbe}}, + "notnivc": {Name: "notnivc", CodePoints: []int{8957}, Characters: []byte{0xe2, 0x8b, 0xbd}}, + "npar": {Name: "npar", CodePoints: []int{8742}, Characters: []byte{0xe2, 0x88, 0xa6}}, + "nparallel": {Name: "nparallel", CodePoints: []int{8742}, Characters: []byte{0xe2, 0x88, 0xa6}}, + "nparsl": {Name: "nparsl", CodePoints: []int{11005, 8421}, Characters: []byte{0xe2, 0xab, 0xbd, 0xe2, 0x83, 0xa5}}, + "npart": {Name: "npart", CodePoints: []int{8706, 824}, Characters: []byte{0xe2, 0x88, 0x82, 0xcc, 0xb8}}, + "npolint": {Name: "npolint", CodePoints: []int{10772}, Characters: []byte{0xe2, 0xa8, 0x94}}, + "npr": {Name: "npr", CodePoints: []int{8832}, Characters: []byte{0xe2, 0x8a, 0x80}}, + "nprcue": {Name: "nprcue", CodePoints: []int{8928}, Characters: []byte{0xe2, 0x8b, 0xa0}}, + "npre": {Name: "npre", CodePoints: []int{10927, 824}, Characters: []byte{0xe2, 0xaa, 0xaf, 0xcc, 0xb8}}, + "nprec": {Name: "nprec", CodePoints: []int{8832}, Characters: []byte{0xe2, 0x8a, 0x80}}, + "npreceq": {Name: "npreceq", CodePoints: []int{10927, 824}, Characters: []byte{0xe2, 0xaa, 0xaf, 0xcc, 0xb8}}, + "nrArr": {Name: "nrArr", CodePoints: []int{8655}, Characters: []byte{0xe2, 0x87, 0x8f}}, + "nrarr": {Name: "nrarr", CodePoints: []int{8603}, Characters: []byte{0xe2, 0x86, 0x9b}}, + "nrarrc": {Name: "nrarrc", CodePoints: []int{10547, 824}, Characters: []byte{0xe2, 0xa4, 0xb3, 0xcc, 0xb8}}, + "nrarrw": {Name: "nrarrw", CodePoints: []int{8605, 824}, Characters: []byte{0xe2, 0x86, 0x9d, 0xcc, 0xb8}}, + "nrightarrow": {Name: "nrightarrow", CodePoints: []int{8603}, Characters: []byte{0xe2, 0x86, 0x9b}}, + "nrtri": {Name: "nrtri", CodePoints: []int{8939}, Characters: []byte{0xe2, 0x8b, 0xab}}, + "nrtrie": {Name: "nrtrie", CodePoints: []int{8941}, Characters: []byte{0xe2, 0x8b, 0xad}}, + "nsc": {Name: "nsc", CodePoints: []int{8833}, Characters: []byte{0xe2, 0x8a, 0x81}}, + "nsccue": {Name: "nsccue", CodePoints: []int{8929}, Characters: []byte{0xe2, 0x8b, 0xa1}}, + "nsce": {Name: "nsce", CodePoints: []int{10928, 824}, Characters: []byte{0xe2, 0xaa, 0xb0, 0xcc, 0xb8}}, + "nscr": {Name: "nscr", CodePoints: []int{120003}, Characters: []byte{0xf0, 0x9d, 0x93, 0x83}}, + "nshortmid": {Name: "nshortmid", CodePoints: []int{8740}, Characters: []byte{0xe2, 0x88, 0xa4}}, + "nshortparallel": {Name: "nshortparallel", CodePoints: []int{8742}, Characters: []byte{0xe2, 0x88, 0xa6}}, + "nsim": {Name: "nsim", CodePoints: []int{8769}, Characters: []byte{0xe2, 0x89, 0x81}}, + "nsime": {Name: "nsime", CodePoints: []int{8772}, Characters: []byte{0xe2, 0x89, 0x84}}, + "nsimeq": {Name: "nsimeq", CodePoints: []int{8772}, Characters: []byte{0xe2, 0x89, 0x84}}, + "nsmid": {Name: "nsmid", CodePoints: []int{8740}, Characters: []byte{0xe2, 0x88, 0xa4}}, + "nspar": {Name: "nspar", CodePoints: []int{8742}, Characters: []byte{0xe2, 0x88, 0xa6}}, + "nsqsube": {Name: "nsqsube", CodePoints: []int{8930}, Characters: []byte{0xe2, 0x8b, 0xa2}}, + "nsqsupe": {Name: "nsqsupe", CodePoints: []int{8931}, Characters: []byte{0xe2, 0x8b, 0xa3}}, + "nsub": {Name: "nsub", CodePoints: []int{8836}, Characters: []byte{0xe2, 0x8a, 0x84}}, + "nsubE": {Name: "nsubE", CodePoints: []int{10949, 824}, Characters: []byte{0xe2, 0xab, 0x85, 0xcc, 0xb8}}, + "nsube": {Name: "nsube", CodePoints: []int{8840}, Characters: []byte{0xe2, 0x8a, 0x88}}, + "nsubset": {Name: "nsubset", CodePoints: []int{8834, 8402}, Characters: []byte{0xe2, 0x8a, 0x82, 0xe2, 0x83, 0x92}}, + "nsubseteq": {Name: "nsubseteq", CodePoints: []int{8840}, Characters: []byte{0xe2, 0x8a, 0x88}}, + "nsubseteqq": {Name: "nsubseteqq", CodePoints: []int{10949, 824}, Characters: []byte{0xe2, 0xab, 0x85, 0xcc, 0xb8}}, + "nsucc": {Name: "nsucc", CodePoints: []int{8833}, Characters: []byte{0xe2, 0x8a, 0x81}}, + "nsucceq": {Name: "nsucceq", CodePoints: []int{10928, 824}, Characters: []byte{0xe2, 0xaa, 0xb0, 0xcc, 0xb8}}, + "nsup": {Name: "nsup", CodePoints: []int{8837}, Characters: []byte{0xe2, 0x8a, 0x85}}, + "nsupE": {Name: "nsupE", CodePoints: []int{10950, 824}, Characters: []byte{0xe2, 0xab, 0x86, 0xcc, 0xb8}}, + "nsupe": {Name: "nsupe", CodePoints: []int{8841}, Characters: []byte{0xe2, 0x8a, 0x89}}, + "nsupset": {Name: "nsupset", CodePoints: []int{8835, 8402}, Characters: []byte{0xe2, 0x8a, 0x83, 0xe2, 0x83, 0x92}}, + "nsupseteq": {Name: "nsupseteq", CodePoints: []int{8841}, Characters: []byte{0xe2, 0x8a, 0x89}}, + "nsupseteqq": {Name: "nsupseteqq", CodePoints: []int{10950, 824}, Characters: []byte{0xe2, 0xab, 0x86, 0xcc, 0xb8}}, + "ntgl": {Name: "ntgl", CodePoints: []int{8825}, Characters: []byte{0xe2, 0x89, 0xb9}}, + "ntilde": {Name: "ntilde", CodePoints: []int{241}, Characters: []byte{0xc3, 0xb1}}, + "ntlg": {Name: "ntlg", CodePoints: []int{8824}, Characters: []byte{0xe2, 0x89, 0xb8}}, + "ntriangleleft": {Name: "ntriangleleft", CodePoints: []int{8938}, Characters: []byte{0xe2, 0x8b, 0xaa}}, + "ntrianglelefteq": {Name: "ntrianglelefteq", CodePoints: []int{8940}, Characters: []byte{0xe2, 0x8b, 0xac}}, + "ntriangleright": {Name: "ntriangleright", CodePoints: []int{8939}, Characters: []byte{0xe2, 0x8b, 0xab}}, + "ntrianglerighteq": {Name: "ntrianglerighteq", CodePoints: []int{8941}, Characters: []byte{0xe2, 0x8b, 0xad}}, + "nu": {Name: "nu", CodePoints: []int{957}, Characters: []byte{0xce, 0xbd}}, + "num": {Name: "num", CodePoints: []int{35}, Characters: []byte{0x23}}, + "numero": {Name: "numero", CodePoints: []int{8470}, Characters: []byte{0xe2, 0x84, 0x96}}, + "numsp": {Name: "numsp", CodePoints: []int{8199}, Characters: []byte{0xe2, 0x80, 0x87}}, + "nvDash": {Name: "nvDash", CodePoints: []int{8877}, Characters: []byte{0xe2, 0x8a, 0xad}}, + "nvHarr": {Name: "nvHarr", CodePoints: []int{10500}, Characters: []byte{0xe2, 0xa4, 0x84}}, + "nvap": {Name: "nvap", CodePoints: []int{8781, 8402}, Characters: []byte{0xe2, 0x89, 0x8d, 0xe2, 0x83, 0x92}}, + "nvdash": {Name: "nvdash", CodePoints: []int{8876}, Characters: []byte{0xe2, 0x8a, 0xac}}, + "nvge": {Name: "nvge", CodePoints: []int{8805, 8402}, Characters: []byte{0xe2, 0x89, 0xa5, 0xe2, 0x83, 0x92}}, + "nvgt": {Name: "nvgt", CodePoints: []int{62, 8402}, Characters: []byte{0x3e, 0xe2, 0x83, 0x92}}, + "nvinfin": {Name: "nvinfin", CodePoints: []int{10718}, Characters: []byte{0xe2, 0xa7, 0x9e}}, + "nvlArr": {Name: "nvlArr", CodePoints: []int{10498}, Characters: []byte{0xe2, 0xa4, 0x82}}, + "nvle": {Name: "nvle", CodePoints: []int{8804, 8402}, Characters: []byte{0xe2, 0x89, 0xa4, 0xe2, 0x83, 0x92}}, + "nvlt": {Name: "nvlt", CodePoints: []int{60, 8402}, Characters: []byte{0x3c, 0xe2, 0x83, 0x92}}, + "nvltrie": {Name: "nvltrie", CodePoints: []int{8884, 8402}, Characters: []byte{0xe2, 0x8a, 0xb4, 0xe2, 0x83, 0x92}}, + "nvrArr": {Name: "nvrArr", CodePoints: []int{10499}, Characters: []byte{0xe2, 0xa4, 0x83}}, + "nvrtrie": {Name: "nvrtrie", CodePoints: []int{8885, 8402}, Characters: []byte{0xe2, 0x8a, 0xb5, 0xe2, 0x83, 0x92}}, + "nvsim": {Name: "nvsim", CodePoints: []int{8764, 8402}, Characters: []byte{0xe2, 0x88, 0xbc, 0xe2, 0x83, 0x92}}, + "nwArr": {Name: "nwArr", CodePoints: []int{8662}, Characters: []byte{0xe2, 0x87, 0x96}}, + "nwarhk": {Name: "nwarhk", CodePoints: []int{10531}, Characters: []byte{0xe2, 0xa4, 0xa3}}, + "nwarr": {Name: "nwarr", CodePoints: []int{8598}, Characters: []byte{0xe2, 0x86, 0x96}}, + "nwarrow": {Name: "nwarrow", CodePoints: []int{8598}, Characters: []byte{0xe2, 0x86, 0x96}}, + "nwnear": {Name: "nwnear", CodePoints: []int{10535}, Characters: []byte{0xe2, 0xa4, 0xa7}}, + "oS": {Name: "oS", CodePoints: []int{9416}, Characters: []byte{0xe2, 0x93, 0x88}}, + "oacute": {Name: "oacute", CodePoints: []int{243}, Characters: []byte{0xc3, 0xb3}}, + "oast": {Name: "oast", CodePoints: []int{8859}, Characters: []byte{0xe2, 0x8a, 0x9b}}, + "ocir": {Name: "ocir", CodePoints: []int{8858}, Characters: []byte{0xe2, 0x8a, 0x9a}}, + "ocirc": {Name: "ocirc", CodePoints: []int{244}, Characters: []byte{0xc3, 0xb4}}, + "ocy": {Name: "ocy", CodePoints: []int{1086}, Characters: []byte{0xd0, 0xbe}}, + "odash": {Name: "odash", CodePoints: []int{8861}, Characters: []byte{0xe2, 0x8a, 0x9d}}, + "odblac": {Name: "odblac", CodePoints: []int{337}, Characters: []byte{0xc5, 0x91}}, + "odiv": {Name: "odiv", CodePoints: []int{10808}, Characters: []byte{0xe2, 0xa8, 0xb8}}, + "odot": {Name: "odot", CodePoints: []int{8857}, Characters: []byte{0xe2, 0x8a, 0x99}}, + "odsold": {Name: "odsold", CodePoints: []int{10684}, Characters: []byte{0xe2, 0xa6, 0xbc}}, + "oelig": {Name: "oelig", CodePoints: []int{339}, Characters: []byte{0xc5, 0x93}}, + "ofcir": {Name: "ofcir", CodePoints: []int{10687}, Characters: []byte{0xe2, 0xa6, 0xbf}}, + "ofr": {Name: "ofr", CodePoints: []int{120108}, Characters: []byte{0xf0, 0x9d, 0x94, 0xac}}, + "ogon": {Name: "ogon", CodePoints: []int{731}, Characters: []byte{0xcb, 0x9b}}, + "ograve": {Name: "ograve", CodePoints: []int{242}, Characters: []byte{0xc3, 0xb2}}, + "ogt": {Name: "ogt", CodePoints: []int{10689}, Characters: []byte{0xe2, 0xa7, 0x81}}, + "ohbar": {Name: "ohbar", CodePoints: []int{10677}, Characters: []byte{0xe2, 0xa6, 0xb5}}, + "ohm": {Name: "ohm", CodePoints: []int{937}, Characters: []byte{0xce, 0xa9}}, + "oint": {Name: "oint", CodePoints: []int{8750}, Characters: []byte{0xe2, 0x88, 0xae}}, + "olarr": {Name: "olarr", CodePoints: []int{8634}, Characters: []byte{0xe2, 0x86, 0xba}}, + "olcir": {Name: "olcir", CodePoints: []int{10686}, Characters: []byte{0xe2, 0xa6, 0xbe}}, + "olcross": {Name: "olcross", CodePoints: []int{10683}, Characters: []byte{0xe2, 0xa6, 0xbb}}, + "oline": {Name: "oline", CodePoints: []int{8254}, Characters: []byte{0xe2, 0x80, 0xbe}}, + "olt": {Name: "olt", CodePoints: []int{10688}, Characters: []byte{0xe2, 0xa7, 0x80}}, + "omacr": {Name: "omacr", CodePoints: []int{333}, Characters: []byte{0xc5, 0x8d}}, + "omega": {Name: "omega", CodePoints: []int{969}, Characters: []byte{0xcf, 0x89}}, + "omicron": {Name: "omicron", CodePoints: []int{959}, Characters: []byte{0xce, 0xbf}}, + "omid": {Name: "omid", CodePoints: []int{10678}, Characters: []byte{0xe2, 0xa6, 0xb6}}, + "ominus": {Name: "ominus", CodePoints: []int{8854}, Characters: []byte{0xe2, 0x8a, 0x96}}, + "oopf": {Name: "oopf", CodePoints: []int{120160}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa0}}, + "opar": {Name: "opar", CodePoints: []int{10679}, Characters: []byte{0xe2, 0xa6, 0xb7}}, + "operp": {Name: "operp", CodePoints: []int{10681}, Characters: []byte{0xe2, 0xa6, 0xb9}}, + "oplus": {Name: "oplus", CodePoints: []int{8853}, Characters: []byte{0xe2, 0x8a, 0x95}}, + "or": {Name: "or", CodePoints: []int{8744}, Characters: []byte{0xe2, 0x88, 0xa8}}, + "orarr": {Name: "orarr", CodePoints: []int{8635}, Characters: []byte{0xe2, 0x86, 0xbb}}, + "ord": {Name: "ord", CodePoints: []int{10845}, Characters: []byte{0xe2, 0xa9, 0x9d}}, + "order": {Name: "order", CodePoints: []int{8500}, Characters: []byte{0xe2, 0x84, 0xb4}}, + "orderof": {Name: "orderof", CodePoints: []int{8500}, Characters: []byte{0xe2, 0x84, 0xb4}}, + "ordf": {Name: "ordf", CodePoints: []int{170}, Characters: []byte{0xc2, 0xaa}}, + "ordm": {Name: "ordm", CodePoints: []int{186}, Characters: []byte{0xc2, 0xba}}, + "origof": {Name: "origof", CodePoints: []int{8886}, Characters: []byte{0xe2, 0x8a, 0xb6}}, + "oror": {Name: "oror", CodePoints: []int{10838}, Characters: []byte{0xe2, 0xa9, 0x96}}, + "orslope": {Name: "orslope", CodePoints: []int{10839}, Characters: []byte{0xe2, 0xa9, 0x97}}, + "orv": {Name: "orv", CodePoints: []int{10843}, Characters: []byte{0xe2, 0xa9, 0x9b}}, + "oscr": {Name: "oscr", CodePoints: []int{8500}, Characters: []byte{0xe2, 0x84, 0xb4}}, + "oslash": {Name: "oslash", CodePoints: []int{248}, Characters: []byte{0xc3, 0xb8}}, + "osol": {Name: "osol", CodePoints: []int{8856}, Characters: []byte{0xe2, 0x8a, 0x98}}, + "otilde": {Name: "otilde", CodePoints: []int{245}, Characters: []byte{0xc3, 0xb5}}, + "otimes": {Name: "otimes", CodePoints: []int{8855}, Characters: []byte{0xe2, 0x8a, 0x97}}, + "otimesas": {Name: "otimesas", CodePoints: []int{10806}, Characters: []byte{0xe2, 0xa8, 0xb6}}, + "ouml": {Name: "ouml", CodePoints: []int{246}, Characters: []byte{0xc3, 0xb6}}, + "ovbar": {Name: "ovbar", CodePoints: []int{9021}, Characters: []byte{0xe2, 0x8c, 0xbd}}, + "par": {Name: "par", CodePoints: []int{8741}, Characters: []byte{0xe2, 0x88, 0xa5}}, + "para": {Name: "para", CodePoints: []int{182}, Characters: []byte{0xc2, 0xb6}}, + "parallel": {Name: "parallel", CodePoints: []int{8741}, Characters: []byte{0xe2, 0x88, 0xa5}}, + "parsim": {Name: "parsim", CodePoints: []int{10995}, Characters: []byte{0xe2, 0xab, 0xb3}}, + "parsl": {Name: "parsl", CodePoints: []int{11005}, Characters: []byte{0xe2, 0xab, 0xbd}}, + "part": {Name: "part", CodePoints: []int{8706}, Characters: []byte{0xe2, 0x88, 0x82}}, + "pcy": {Name: "pcy", CodePoints: []int{1087}, Characters: []byte{0xd0, 0xbf}}, + "percnt": {Name: "percnt", CodePoints: []int{37}, Characters: []byte{0x25}}, + "period": {Name: "period", CodePoints: []int{46}, Characters: []byte{0x2e}}, + "permil": {Name: "permil", CodePoints: []int{8240}, Characters: []byte{0xe2, 0x80, 0xb0}}, + "perp": {Name: "perp", CodePoints: []int{8869}, Characters: []byte{0xe2, 0x8a, 0xa5}}, + "pertenk": {Name: "pertenk", CodePoints: []int{8241}, Characters: []byte{0xe2, 0x80, 0xb1}}, + "pfr": {Name: "pfr", CodePoints: []int{120109}, Characters: []byte{0xf0, 0x9d, 0x94, 0xad}}, + "phi": {Name: "phi", CodePoints: []int{966}, Characters: []byte{0xcf, 0x86}}, + "phiv": {Name: "phiv", CodePoints: []int{981}, Characters: []byte{0xcf, 0x95}}, + "phmmat": {Name: "phmmat", CodePoints: []int{8499}, Characters: []byte{0xe2, 0x84, 0xb3}}, + "phone": {Name: "phone", CodePoints: []int{9742}, Characters: []byte{0xe2, 0x98, 0x8e}}, + "pi": {Name: "pi", CodePoints: []int{960}, Characters: []byte{0xcf, 0x80}}, + "pitchfork": {Name: "pitchfork", CodePoints: []int{8916}, Characters: []byte{0xe2, 0x8b, 0x94}}, + "piv": {Name: "piv", CodePoints: []int{982}, Characters: []byte{0xcf, 0x96}}, + "planck": {Name: "planck", CodePoints: []int{8463}, Characters: []byte{0xe2, 0x84, 0x8f}}, + "planckh": {Name: "planckh", CodePoints: []int{8462}, Characters: []byte{0xe2, 0x84, 0x8e}}, + "plankv": {Name: "plankv", CodePoints: []int{8463}, Characters: []byte{0xe2, 0x84, 0x8f}}, + "plus": {Name: "plus", CodePoints: []int{43}, Characters: []byte{0x2b}}, + "plusacir": {Name: "plusacir", CodePoints: []int{10787}, Characters: []byte{0xe2, 0xa8, 0xa3}}, + "plusb": {Name: "plusb", CodePoints: []int{8862}, Characters: []byte{0xe2, 0x8a, 0x9e}}, + "pluscir": {Name: "pluscir", CodePoints: []int{10786}, Characters: []byte{0xe2, 0xa8, 0xa2}}, + "plusdo": {Name: "plusdo", CodePoints: []int{8724}, Characters: []byte{0xe2, 0x88, 0x94}}, + "plusdu": {Name: "plusdu", CodePoints: []int{10789}, Characters: []byte{0xe2, 0xa8, 0xa5}}, + "pluse": {Name: "pluse", CodePoints: []int{10866}, Characters: []byte{0xe2, 0xa9, 0xb2}}, + "plusmn": {Name: "plusmn", CodePoints: []int{177}, Characters: []byte{0xc2, 0xb1}}, + "plussim": {Name: "plussim", CodePoints: []int{10790}, Characters: []byte{0xe2, 0xa8, 0xa6}}, + "plustwo": {Name: "plustwo", CodePoints: []int{10791}, Characters: []byte{0xe2, 0xa8, 0xa7}}, + "pm": {Name: "pm", CodePoints: []int{177}, Characters: []byte{0xc2, 0xb1}}, + "pointint": {Name: "pointint", CodePoints: []int{10773}, Characters: []byte{0xe2, 0xa8, 0x95}}, + "popf": {Name: "popf", CodePoints: []int{120161}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa1}}, + "pound": {Name: "pound", CodePoints: []int{163}, Characters: []byte{0xc2, 0xa3}}, + "pr": {Name: "pr", CodePoints: []int{8826}, Characters: []byte{0xe2, 0x89, 0xba}}, + "prE": {Name: "prE", CodePoints: []int{10931}, Characters: []byte{0xe2, 0xaa, 0xb3}}, + "prap": {Name: "prap", CodePoints: []int{10935}, Characters: []byte{0xe2, 0xaa, 0xb7}}, + "prcue": {Name: "prcue", CodePoints: []int{8828}, Characters: []byte{0xe2, 0x89, 0xbc}}, + "pre": {Name: "pre", CodePoints: []int{10927}, Characters: []byte{0xe2, 0xaa, 0xaf}}, + "prec": {Name: "prec", CodePoints: []int{8826}, Characters: []byte{0xe2, 0x89, 0xba}}, + "precapprox": {Name: "precapprox", CodePoints: []int{10935}, Characters: []byte{0xe2, 0xaa, 0xb7}}, + "preccurlyeq": {Name: "preccurlyeq", CodePoints: []int{8828}, Characters: []byte{0xe2, 0x89, 0xbc}}, + "preceq": {Name: "preceq", CodePoints: []int{10927}, Characters: []byte{0xe2, 0xaa, 0xaf}}, + "precnapprox": {Name: "precnapprox", CodePoints: []int{10937}, Characters: []byte{0xe2, 0xaa, 0xb9}}, + "precneqq": {Name: "precneqq", CodePoints: []int{10933}, Characters: []byte{0xe2, 0xaa, 0xb5}}, + "precnsim": {Name: "precnsim", CodePoints: []int{8936}, Characters: []byte{0xe2, 0x8b, 0xa8}}, + "precsim": {Name: "precsim", CodePoints: []int{8830}, Characters: []byte{0xe2, 0x89, 0xbe}}, + "prime": {Name: "prime", CodePoints: []int{8242}, Characters: []byte{0xe2, 0x80, 0xb2}}, + "primes": {Name: "primes", CodePoints: []int{8473}, Characters: []byte{0xe2, 0x84, 0x99}}, + "prnE": {Name: "prnE", CodePoints: []int{10933}, Characters: []byte{0xe2, 0xaa, 0xb5}}, + "prnap": {Name: "prnap", CodePoints: []int{10937}, Characters: []byte{0xe2, 0xaa, 0xb9}}, + "prnsim": {Name: "prnsim", CodePoints: []int{8936}, Characters: []byte{0xe2, 0x8b, 0xa8}}, + "prod": {Name: "prod", CodePoints: []int{8719}, Characters: []byte{0xe2, 0x88, 0x8f}}, + "profalar": {Name: "profalar", CodePoints: []int{9006}, Characters: []byte{0xe2, 0x8c, 0xae}}, + "profline": {Name: "profline", CodePoints: []int{8978}, Characters: []byte{0xe2, 0x8c, 0x92}}, + "profsurf": {Name: "profsurf", CodePoints: []int{8979}, Characters: []byte{0xe2, 0x8c, 0x93}}, + "prop": {Name: "prop", CodePoints: []int{8733}, Characters: []byte{0xe2, 0x88, 0x9d}}, + "propto": {Name: "propto", CodePoints: []int{8733}, Characters: []byte{0xe2, 0x88, 0x9d}}, + "prsim": {Name: "prsim", CodePoints: []int{8830}, Characters: []byte{0xe2, 0x89, 0xbe}}, + "prurel": {Name: "prurel", CodePoints: []int{8880}, Characters: []byte{0xe2, 0x8a, 0xb0}}, + "pscr": {Name: "pscr", CodePoints: []int{120005}, Characters: []byte{0xf0, 0x9d, 0x93, 0x85}}, + "psi": {Name: "psi", CodePoints: []int{968}, Characters: []byte{0xcf, 0x88}}, + "puncsp": {Name: "puncsp", CodePoints: []int{8200}, Characters: []byte{0xe2, 0x80, 0x88}}, + "qfr": {Name: "qfr", CodePoints: []int{120110}, Characters: []byte{0xf0, 0x9d, 0x94, 0xae}}, + "qint": {Name: "qint", CodePoints: []int{10764}, Characters: []byte{0xe2, 0xa8, 0x8c}}, + "qopf": {Name: "qopf", CodePoints: []int{120162}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa2}}, + "qprime": {Name: "qprime", CodePoints: []int{8279}, Characters: []byte{0xe2, 0x81, 0x97}}, + "qscr": {Name: "qscr", CodePoints: []int{120006}, Characters: []byte{0xf0, 0x9d, 0x93, 0x86}}, + "quaternions": {Name: "quaternions", CodePoints: []int{8461}, Characters: []byte{0xe2, 0x84, 0x8d}}, + "quatint": {Name: "quatint", CodePoints: []int{10774}, Characters: []byte{0xe2, 0xa8, 0x96}}, + "quest": {Name: "quest", CodePoints: []int{63}, Characters: []byte{0x3f}}, + "questeq": {Name: "questeq", CodePoints: []int{8799}, Characters: []byte{0xe2, 0x89, 0x9f}}, + "quot": {Name: "quot", CodePoints: []int{34}, Characters: []byte{0x22}}, + "rAarr": {Name: "rAarr", CodePoints: []int{8667}, Characters: []byte{0xe2, 0x87, 0x9b}}, + "rArr": {Name: "rArr", CodePoints: []int{8658}, Characters: []byte{0xe2, 0x87, 0x92}}, + "rAtail": {Name: "rAtail", CodePoints: []int{10524}, Characters: []byte{0xe2, 0xa4, 0x9c}}, + "rBarr": {Name: "rBarr", CodePoints: []int{10511}, Characters: []byte{0xe2, 0xa4, 0x8f}}, + "rHar": {Name: "rHar", CodePoints: []int{10596}, Characters: []byte{0xe2, 0xa5, 0xa4}}, + "race": {Name: "race", CodePoints: []int{8765, 817}, Characters: []byte{0xe2, 0x88, 0xbd, 0xcc, 0xb1}}, + "racute": {Name: "racute", CodePoints: []int{341}, Characters: []byte{0xc5, 0x95}}, + "radic": {Name: "radic", CodePoints: []int{8730}, Characters: []byte{0xe2, 0x88, 0x9a}}, + "raemptyv": {Name: "raemptyv", CodePoints: []int{10675}, Characters: []byte{0xe2, 0xa6, 0xb3}}, + "rang": {Name: "rang", CodePoints: []int{10217}, Characters: []byte{0xe2, 0x9f, 0xa9}}, + "rangd": {Name: "rangd", CodePoints: []int{10642}, Characters: []byte{0xe2, 0xa6, 0x92}}, + "range": {Name: "range", CodePoints: []int{10661}, Characters: []byte{0xe2, 0xa6, 0xa5}}, + "rangle": {Name: "rangle", CodePoints: []int{10217}, Characters: []byte{0xe2, 0x9f, 0xa9}}, + "raquo": {Name: "raquo", CodePoints: []int{187}, Characters: []byte{0xc2, 0xbb}}, + "rarr": {Name: "rarr", CodePoints: []int{8594}, Characters: []byte{0xe2, 0x86, 0x92}}, + "rarrap": {Name: "rarrap", CodePoints: []int{10613}, Characters: []byte{0xe2, 0xa5, 0xb5}}, + "rarrb": {Name: "rarrb", CodePoints: []int{8677}, Characters: []byte{0xe2, 0x87, 0xa5}}, + "rarrbfs": {Name: "rarrbfs", CodePoints: []int{10528}, Characters: []byte{0xe2, 0xa4, 0xa0}}, + "rarrc": {Name: "rarrc", CodePoints: []int{10547}, Characters: []byte{0xe2, 0xa4, 0xb3}}, + "rarrfs": {Name: "rarrfs", CodePoints: []int{10526}, Characters: []byte{0xe2, 0xa4, 0x9e}}, + "rarrhk": {Name: "rarrhk", CodePoints: []int{8618}, Characters: []byte{0xe2, 0x86, 0xaa}}, + "rarrlp": {Name: "rarrlp", CodePoints: []int{8620}, Characters: []byte{0xe2, 0x86, 0xac}}, + "rarrpl": {Name: "rarrpl", CodePoints: []int{10565}, Characters: []byte{0xe2, 0xa5, 0x85}}, + "rarrsim": {Name: "rarrsim", CodePoints: []int{10612}, Characters: []byte{0xe2, 0xa5, 0xb4}}, + "rarrtl": {Name: "rarrtl", CodePoints: []int{8611}, Characters: []byte{0xe2, 0x86, 0xa3}}, + "rarrw": {Name: "rarrw", CodePoints: []int{8605}, Characters: []byte{0xe2, 0x86, 0x9d}}, + "ratail": {Name: "ratail", CodePoints: []int{10522}, Characters: []byte{0xe2, 0xa4, 0x9a}}, + "ratio": {Name: "ratio", CodePoints: []int{8758}, Characters: []byte{0xe2, 0x88, 0xb6}}, + "rationals": {Name: "rationals", CodePoints: []int{8474}, Characters: []byte{0xe2, 0x84, 0x9a}}, + "rbarr": {Name: "rbarr", CodePoints: []int{10509}, Characters: []byte{0xe2, 0xa4, 0x8d}}, + "rbbrk": {Name: "rbbrk", CodePoints: []int{10099}, Characters: []byte{0xe2, 0x9d, 0xb3}}, + "rbrace": {Name: "rbrace", CodePoints: []int{125}, Characters: []byte{0x7d}}, + "rbrack": {Name: "rbrack", CodePoints: []int{93}, Characters: []byte{0x5d}}, + "rbrke": {Name: "rbrke", CodePoints: []int{10636}, Characters: []byte{0xe2, 0xa6, 0x8c}}, + "rbrksld": {Name: "rbrksld", CodePoints: []int{10638}, Characters: []byte{0xe2, 0xa6, 0x8e}}, + "rbrkslu": {Name: "rbrkslu", CodePoints: []int{10640}, Characters: []byte{0xe2, 0xa6, 0x90}}, + "rcaron": {Name: "rcaron", CodePoints: []int{345}, Characters: []byte{0xc5, 0x99}}, + "rcedil": {Name: "rcedil", CodePoints: []int{343}, Characters: []byte{0xc5, 0x97}}, + "rceil": {Name: "rceil", CodePoints: []int{8969}, Characters: []byte{0xe2, 0x8c, 0x89}}, + "rcub": {Name: "rcub", CodePoints: []int{125}, Characters: []byte{0x7d}}, + "rcy": {Name: "rcy", CodePoints: []int{1088}, Characters: []byte{0xd1, 0x80}}, + "rdca": {Name: "rdca", CodePoints: []int{10551}, Characters: []byte{0xe2, 0xa4, 0xb7}}, + "rdldhar": {Name: "rdldhar", CodePoints: []int{10601}, Characters: []byte{0xe2, 0xa5, 0xa9}}, + "rdquo": {Name: "rdquo", CodePoints: []int{8221}, Characters: []byte{0xe2, 0x80, 0x9d}}, + "rdquor": {Name: "rdquor", CodePoints: []int{8221}, Characters: []byte{0xe2, 0x80, 0x9d}}, + "rdsh": {Name: "rdsh", CodePoints: []int{8627}, Characters: []byte{0xe2, 0x86, 0xb3}}, + "real": {Name: "real", CodePoints: []int{8476}, Characters: []byte{0xe2, 0x84, 0x9c}}, + "realine": {Name: "realine", CodePoints: []int{8475}, Characters: []byte{0xe2, 0x84, 0x9b}}, + "realpart": {Name: "realpart", CodePoints: []int{8476}, Characters: []byte{0xe2, 0x84, 0x9c}}, + "reals": {Name: "reals", CodePoints: []int{8477}, Characters: []byte{0xe2, 0x84, 0x9d}}, + "rect": {Name: "rect", CodePoints: []int{9645}, Characters: []byte{0xe2, 0x96, 0xad}}, + "reg": {Name: "reg", CodePoints: []int{174}, Characters: []byte{0xc2, 0xae}}, + "rfisht": {Name: "rfisht", CodePoints: []int{10621}, Characters: []byte{0xe2, 0xa5, 0xbd}}, + "rfloor": {Name: "rfloor", CodePoints: []int{8971}, Characters: []byte{0xe2, 0x8c, 0x8b}}, + "rfr": {Name: "rfr", CodePoints: []int{120111}, Characters: []byte{0xf0, 0x9d, 0x94, 0xaf}}, + "rhard": {Name: "rhard", CodePoints: []int{8641}, Characters: []byte{0xe2, 0x87, 0x81}}, + "rharu": {Name: "rharu", CodePoints: []int{8640}, Characters: []byte{0xe2, 0x87, 0x80}}, + "rharul": {Name: "rharul", CodePoints: []int{10604}, Characters: []byte{0xe2, 0xa5, 0xac}}, + "rho": {Name: "rho", CodePoints: []int{961}, Characters: []byte{0xcf, 0x81}}, + "rhov": {Name: "rhov", CodePoints: []int{1009}, Characters: []byte{0xcf, 0xb1}}, + "rightarrow": {Name: "rightarrow", CodePoints: []int{8594}, Characters: []byte{0xe2, 0x86, 0x92}}, + "rightarrowtail": {Name: "rightarrowtail", CodePoints: []int{8611}, Characters: []byte{0xe2, 0x86, 0xa3}}, + "rightharpoondown": {Name: "rightharpoondown", CodePoints: []int{8641}, Characters: []byte{0xe2, 0x87, 0x81}}, + "rightharpoonup": {Name: "rightharpoonup", CodePoints: []int{8640}, Characters: []byte{0xe2, 0x87, 0x80}}, + "rightleftarrows": {Name: "rightleftarrows", CodePoints: []int{8644}, Characters: []byte{0xe2, 0x87, 0x84}}, + "rightleftharpoons": {Name: "rightleftharpoons", CodePoints: []int{8652}, Characters: []byte{0xe2, 0x87, 0x8c}}, + "rightrightarrows": {Name: "rightrightarrows", CodePoints: []int{8649}, Characters: []byte{0xe2, 0x87, 0x89}}, + "rightsquigarrow": {Name: "rightsquigarrow", CodePoints: []int{8605}, Characters: []byte{0xe2, 0x86, 0x9d}}, + "rightthreetimes": {Name: "rightthreetimes", CodePoints: []int{8908}, Characters: []byte{0xe2, 0x8b, 0x8c}}, + "ring": {Name: "ring", CodePoints: []int{730}, Characters: []byte{0xcb, 0x9a}}, + "risingdotseq": {Name: "risingdotseq", CodePoints: []int{8787}, Characters: []byte{0xe2, 0x89, 0x93}}, + "rlarr": {Name: "rlarr", CodePoints: []int{8644}, Characters: []byte{0xe2, 0x87, 0x84}}, + "rlhar": {Name: "rlhar", CodePoints: []int{8652}, Characters: []byte{0xe2, 0x87, 0x8c}}, + "rlm": {Name: "rlm", CodePoints: []int{8207}, Characters: []byte{0xe2, 0x80, 0x8f}}, + "rmoust": {Name: "rmoust", CodePoints: []int{9137}, Characters: []byte{0xe2, 0x8e, 0xb1}}, + "rmoustache": {Name: "rmoustache", CodePoints: []int{9137}, Characters: []byte{0xe2, 0x8e, 0xb1}}, + "rnmid": {Name: "rnmid", CodePoints: []int{10990}, Characters: []byte{0xe2, 0xab, 0xae}}, + "roang": {Name: "roang", CodePoints: []int{10221}, Characters: []byte{0xe2, 0x9f, 0xad}}, + "roarr": {Name: "roarr", CodePoints: []int{8702}, Characters: []byte{0xe2, 0x87, 0xbe}}, + "robrk": {Name: "robrk", CodePoints: []int{10215}, Characters: []byte{0xe2, 0x9f, 0xa7}}, + "ropar": {Name: "ropar", CodePoints: []int{10630}, Characters: []byte{0xe2, 0xa6, 0x86}}, + "ropf": {Name: "ropf", CodePoints: []int{120163}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa3}}, + "roplus": {Name: "roplus", CodePoints: []int{10798}, Characters: []byte{0xe2, 0xa8, 0xae}}, + "rotimes": {Name: "rotimes", CodePoints: []int{10805}, Characters: []byte{0xe2, 0xa8, 0xb5}}, + "rpar": {Name: "rpar", CodePoints: []int{41}, Characters: []byte{0x29}}, + "rpargt": {Name: "rpargt", CodePoints: []int{10644}, Characters: []byte{0xe2, 0xa6, 0x94}}, + "rppolint": {Name: "rppolint", CodePoints: []int{10770}, Characters: []byte{0xe2, 0xa8, 0x92}}, + "rrarr": {Name: "rrarr", CodePoints: []int{8649}, Characters: []byte{0xe2, 0x87, 0x89}}, + "rsaquo": {Name: "rsaquo", CodePoints: []int{8250}, Characters: []byte{0xe2, 0x80, 0xba}}, + "rscr": {Name: "rscr", CodePoints: []int{120007}, Characters: []byte{0xf0, 0x9d, 0x93, 0x87}}, + "rsh": {Name: "rsh", CodePoints: []int{8625}, Characters: []byte{0xe2, 0x86, 0xb1}}, + "rsqb": {Name: "rsqb", CodePoints: []int{93}, Characters: []byte{0x5d}}, + "rsquo": {Name: "rsquo", CodePoints: []int{8217}, Characters: []byte{0xe2, 0x80, 0x99}}, + "rsquor": {Name: "rsquor", CodePoints: []int{8217}, Characters: []byte{0xe2, 0x80, 0x99}}, + "rthree": {Name: "rthree", CodePoints: []int{8908}, Characters: []byte{0xe2, 0x8b, 0x8c}}, + "rtimes": {Name: "rtimes", CodePoints: []int{8906}, Characters: []byte{0xe2, 0x8b, 0x8a}}, + "rtri": {Name: "rtri", CodePoints: []int{9657}, Characters: []byte{0xe2, 0x96, 0xb9}}, + "rtrie": {Name: "rtrie", CodePoints: []int{8885}, Characters: []byte{0xe2, 0x8a, 0xb5}}, + "rtrif": {Name: "rtrif", CodePoints: []int{9656}, Characters: []byte{0xe2, 0x96, 0xb8}}, + "rtriltri": {Name: "rtriltri", CodePoints: []int{10702}, Characters: []byte{0xe2, 0xa7, 0x8e}}, + "ruluhar": {Name: "ruluhar", CodePoints: []int{10600}, Characters: []byte{0xe2, 0xa5, 0xa8}}, + "rx": {Name: "rx", CodePoints: []int{8478}, Characters: []byte{0xe2, 0x84, 0x9e}}, + "sacute": {Name: "sacute", CodePoints: []int{347}, Characters: []byte{0xc5, 0x9b}}, + "sbquo": {Name: "sbquo", CodePoints: []int{8218}, Characters: []byte{0xe2, 0x80, 0x9a}}, + "sc": {Name: "sc", CodePoints: []int{8827}, Characters: []byte{0xe2, 0x89, 0xbb}}, + "scE": {Name: "scE", CodePoints: []int{10932}, Characters: []byte{0xe2, 0xaa, 0xb4}}, + "scap": {Name: "scap", CodePoints: []int{10936}, Characters: []byte{0xe2, 0xaa, 0xb8}}, + "scaron": {Name: "scaron", CodePoints: []int{353}, Characters: []byte{0xc5, 0xa1}}, + "sccue": {Name: "sccue", CodePoints: []int{8829}, Characters: []byte{0xe2, 0x89, 0xbd}}, + "sce": {Name: "sce", CodePoints: []int{10928}, Characters: []byte{0xe2, 0xaa, 0xb0}}, + "scedil": {Name: "scedil", CodePoints: []int{351}, Characters: []byte{0xc5, 0x9f}}, + "scirc": {Name: "scirc", CodePoints: []int{349}, Characters: []byte{0xc5, 0x9d}}, + "scnE": {Name: "scnE", CodePoints: []int{10934}, Characters: []byte{0xe2, 0xaa, 0xb6}}, + "scnap": {Name: "scnap", CodePoints: []int{10938}, Characters: []byte{0xe2, 0xaa, 0xba}}, + "scnsim": {Name: "scnsim", CodePoints: []int{8937}, Characters: []byte{0xe2, 0x8b, 0xa9}}, + "scpolint": {Name: "scpolint", CodePoints: []int{10771}, Characters: []byte{0xe2, 0xa8, 0x93}}, + "scsim": {Name: "scsim", CodePoints: []int{8831}, Characters: []byte{0xe2, 0x89, 0xbf}}, + "scy": {Name: "scy", CodePoints: []int{1089}, Characters: []byte{0xd1, 0x81}}, + "sdot": {Name: "sdot", CodePoints: []int{8901}, Characters: []byte{0xe2, 0x8b, 0x85}}, + "sdotb": {Name: "sdotb", CodePoints: []int{8865}, Characters: []byte{0xe2, 0x8a, 0xa1}}, + "sdote": {Name: "sdote", CodePoints: []int{10854}, Characters: []byte{0xe2, 0xa9, 0xa6}}, + "seArr": {Name: "seArr", CodePoints: []int{8664}, Characters: []byte{0xe2, 0x87, 0x98}}, + "searhk": {Name: "searhk", CodePoints: []int{10533}, Characters: []byte{0xe2, 0xa4, 0xa5}}, + "searr": {Name: "searr", CodePoints: []int{8600}, Characters: []byte{0xe2, 0x86, 0x98}}, + "searrow": {Name: "searrow", CodePoints: []int{8600}, Characters: []byte{0xe2, 0x86, 0x98}}, + "sect": {Name: "sect", CodePoints: []int{167}, Characters: []byte{0xc2, 0xa7}}, + "semi": {Name: "semi", CodePoints: []int{59}, Characters: []byte{0x3b}}, + "seswar": {Name: "seswar", CodePoints: []int{10537}, Characters: []byte{0xe2, 0xa4, 0xa9}}, + "setminus": {Name: "setminus", CodePoints: []int{8726}, Characters: []byte{0xe2, 0x88, 0x96}}, + "setmn": {Name: "setmn", CodePoints: []int{8726}, Characters: []byte{0xe2, 0x88, 0x96}}, + "sext": {Name: "sext", CodePoints: []int{10038}, Characters: []byte{0xe2, 0x9c, 0xb6}}, + "sfr": {Name: "sfr", CodePoints: []int{120112}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb0}}, + "sfrown": {Name: "sfrown", CodePoints: []int{8994}, Characters: []byte{0xe2, 0x8c, 0xa2}}, + "sharp": {Name: "sharp", CodePoints: []int{9839}, Characters: []byte{0xe2, 0x99, 0xaf}}, + "shchcy": {Name: "shchcy", CodePoints: []int{1097}, Characters: []byte{0xd1, 0x89}}, + "shcy": {Name: "shcy", CodePoints: []int{1096}, Characters: []byte{0xd1, 0x88}}, + "shortmid": {Name: "shortmid", CodePoints: []int{8739}, Characters: []byte{0xe2, 0x88, 0xa3}}, + "shortparallel": {Name: "shortparallel", CodePoints: []int{8741}, Characters: []byte{0xe2, 0x88, 0xa5}}, + "shy": {Name: "shy", CodePoints: []int{173}, Characters: []byte{0xc2, 0xad}}, + "sigma": {Name: "sigma", CodePoints: []int{963}, Characters: []byte{0xcf, 0x83}}, + "sigmaf": {Name: "sigmaf", CodePoints: []int{962}, Characters: []byte{0xcf, 0x82}}, + "sigmav": {Name: "sigmav", CodePoints: []int{962}, Characters: []byte{0xcf, 0x82}}, + "sim": {Name: "sim", CodePoints: []int{8764}, Characters: []byte{0xe2, 0x88, 0xbc}}, + "simdot": {Name: "simdot", CodePoints: []int{10858}, Characters: []byte{0xe2, 0xa9, 0xaa}}, + "sime": {Name: "sime", CodePoints: []int{8771}, Characters: []byte{0xe2, 0x89, 0x83}}, + "simeq": {Name: "simeq", CodePoints: []int{8771}, Characters: []byte{0xe2, 0x89, 0x83}}, + "simg": {Name: "simg", CodePoints: []int{10910}, Characters: []byte{0xe2, 0xaa, 0x9e}}, + "simgE": {Name: "simgE", CodePoints: []int{10912}, Characters: []byte{0xe2, 0xaa, 0xa0}}, + "siml": {Name: "siml", CodePoints: []int{10909}, Characters: []byte{0xe2, 0xaa, 0x9d}}, + "simlE": {Name: "simlE", CodePoints: []int{10911}, Characters: []byte{0xe2, 0xaa, 0x9f}}, + "simne": {Name: "simne", CodePoints: []int{8774}, Characters: []byte{0xe2, 0x89, 0x86}}, + "simplus": {Name: "simplus", CodePoints: []int{10788}, Characters: []byte{0xe2, 0xa8, 0xa4}}, + "simrarr": {Name: "simrarr", CodePoints: []int{10610}, Characters: []byte{0xe2, 0xa5, 0xb2}}, + "slarr": {Name: "slarr", CodePoints: []int{8592}, Characters: []byte{0xe2, 0x86, 0x90}}, + "smallsetminus": {Name: "smallsetminus", CodePoints: []int{8726}, Characters: []byte{0xe2, 0x88, 0x96}}, + "smashp": {Name: "smashp", CodePoints: []int{10803}, Characters: []byte{0xe2, 0xa8, 0xb3}}, + "smeparsl": {Name: "smeparsl", CodePoints: []int{10724}, Characters: []byte{0xe2, 0xa7, 0xa4}}, + "smid": {Name: "smid", CodePoints: []int{8739}, Characters: []byte{0xe2, 0x88, 0xa3}}, + "smile": {Name: "smile", CodePoints: []int{8995}, Characters: []byte{0xe2, 0x8c, 0xa3}}, + "smt": {Name: "smt", CodePoints: []int{10922}, Characters: []byte{0xe2, 0xaa, 0xaa}}, + "smte": {Name: "smte", CodePoints: []int{10924}, Characters: []byte{0xe2, 0xaa, 0xac}}, + "smtes": {Name: "smtes", CodePoints: []int{10924, 65024}, Characters: []byte{0xe2, 0xaa, 0xac, 0xef, 0xb8, 0x80}}, + "softcy": {Name: "softcy", CodePoints: []int{1100}, Characters: []byte{0xd1, 0x8c}}, + "sol": {Name: "sol", CodePoints: []int{47}, Characters: []byte{0x2f}}, + "solb": {Name: "solb", CodePoints: []int{10692}, Characters: []byte{0xe2, 0xa7, 0x84}}, + "solbar": {Name: "solbar", CodePoints: []int{9023}, Characters: []byte{0xe2, 0x8c, 0xbf}}, + "sopf": {Name: "sopf", CodePoints: []int{120164}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa4}}, + "spades": {Name: "spades", CodePoints: []int{9824}, Characters: []byte{0xe2, 0x99, 0xa0}}, + "spadesuit": {Name: "spadesuit", CodePoints: []int{9824}, Characters: []byte{0xe2, 0x99, 0xa0}}, + "spar": {Name: "spar", CodePoints: []int{8741}, Characters: []byte{0xe2, 0x88, 0xa5}}, + "sqcap": {Name: "sqcap", CodePoints: []int{8851}, Characters: []byte{0xe2, 0x8a, 0x93}}, + "sqcaps": {Name: "sqcaps", CodePoints: []int{8851, 65024}, Characters: []byte{0xe2, 0x8a, 0x93, 0xef, 0xb8, 0x80}}, + "sqcup": {Name: "sqcup", CodePoints: []int{8852}, Characters: []byte{0xe2, 0x8a, 0x94}}, + "sqcups": {Name: "sqcups", CodePoints: []int{8852, 65024}, Characters: []byte{0xe2, 0x8a, 0x94, 0xef, 0xb8, 0x80}}, + "sqsub": {Name: "sqsub", CodePoints: []int{8847}, Characters: []byte{0xe2, 0x8a, 0x8f}}, + "sqsube": {Name: "sqsube", CodePoints: []int{8849}, Characters: []byte{0xe2, 0x8a, 0x91}}, + "sqsubset": {Name: "sqsubset", CodePoints: []int{8847}, Characters: []byte{0xe2, 0x8a, 0x8f}}, + "sqsubseteq": {Name: "sqsubseteq", CodePoints: []int{8849}, Characters: []byte{0xe2, 0x8a, 0x91}}, + "sqsup": {Name: "sqsup", CodePoints: []int{8848}, Characters: []byte{0xe2, 0x8a, 0x90}}, + "sqsupe": {Name: "sqsupe", CodePoints: []int{8850}, Characters: []byte{0xe2, 0x8a, 0x92}}, + "sqsupset": {Name: "sqsupset", CodePoints: []int{8848}, Characters: []byte{0xe2, 0x8a, 0x90}}, + "sqsupseteq": {Name: "sqsupseteq", CodePoints: []int{8850}, Characters: []byte{0xe2, 0x8a, 0x92}}, + "squ": {Name: "squ", CodePoints: []int{9633}, Characters: []byte{0xe2, 0x96, 0xa1}}, + "square": {Name: "square", CodePoints: []int{9633}, Characters: []byte{0xe2, 0x96, 0xa1}}, + "squarf": {Name: "squarf", CodePoints: []int{9642}, Characters: []byte{0xe2, 0x96, 0xaa}}, + "squf": {Name: "squf", CodePoints: []int{9642}, Characters: []byte{0xe2, 0x96, 0xaa}}, + "srarr": {Name: "srarr", CodePoints: []int{8594}, Characters: []byte{0xe2, 0x86, 0x92}}, + "sscr": {Name: "sscr", CodePoints: []int{120008}, Characters: []byte{0xf0, 0x9d, 0x93, 0x88}}, + "ssetmn": {Name: "ssetmn", CodePoints: []int{8726}, Characters: []byte{0xe2, 0x88, 0x96}}, + "ssmile": {Name: "ssmile", CodePoints: []int{8995}, Characters: []byte{0xe2, 0x8c, 0xa3}}, + "sstarf": {Name: "sstarf", CodePoints: []int{8902}, Characters: []byte{0xe2, 0x8b, 0x86}}, + "star": {Name: "star", CodePoints: []int{9734}, Characters: []byte{0xe2, 0x98, 0x86}}, + "starf": {Name: "starf", CodePoints: []int{9733}, Characters: []byte{0xe2, 0x98, 0x85}}, + "straightepsilon": {Name: "straightepsilon", CodePoints: []int{1013}, Characters: []byte{0xcf, 0xb5}}, + "straightphi": {Name: "straightphi", CodePoints: []int{981}, Characters: []byte{0xcf, 0x95}}, + "strns": {Name: "strns", CodePoints: []int{175}, Characters: []byte{0xc2, 0xaf}}, + "sub": {Name: "sub", CodePoints: []int{8834}, Characters: []byte{0xe2, 0x8a, 0x82}}, + "subE": {Name: "subE", CodePoints: []int{10949}, Characters: []byte{0xe2, 0xab, 0x85}}, + "subdot": {Name: "subdot", CodePoints: []int{10941}, Characters: []byte{0xe2, 0xaa, 0xbd}}, + "sube": {Name: "sube", CodePoints: []int{8838}, Characters: []byte{0xe2, 0x8a, 0x86}}, + "subedot": {Name: "subedot", CodePoints: []int{10947}, Characters: []byte{0xe2, 0xab, 0x83}}, + "submult": {Name: "submult", CodePoints: []int{10945}, Characters: []byte{0xe2, 0xab, 0x81}}, + "subnE": {Name: "subnE", CodePoints: []int{10955}, Characters: []byte{0xe2, 0xab, 0x8b}}, + "subne": {Name: "subne", CodePoints: []int{8842}, Characters: []byte{0xe2, 0x8a, 0x8a}}, + "subplus": {Name: "subplus", CodePoints: []int{10943}, Characters: []byte{0xe2, 0xaa, 0xbf}}, + "subrarr": {Name: "subrarr", CodePoints: []int{10617}, Characters: []byte{0xe2, 0xa5, 0xb9}}, + "subset": {Name: "subset", CodePoints: []int{8834}, Characters: []byte{0xe2, 0x8a, 0x82}}, + "subseteq": {Name: "subseteq", CodePoints: []int{8838}, Characters: []byte{0xe2, 0x8a, 0x86}}, + "subseteqq": {Name: "subseteqq", CodePoints: []int{10949}, Characters: []byte{0xe2, 0xab, 0x85}}, + "subsetneq": {Name: "subsetneq", CodePoints: []int{8842}, Characters: []byte{0xe2, 0x8a, 0x8a}}, + "subsetneqq": {Name: "subsetneqq", CodePoints: []int{10955}, Characters: []byte{0xe2, 0xab, 0x8b}}, + "subsim": {Name: "subsim", CodePoints: []int{10951}, Characters: []byte{0xe2, 0xab, 0x87}}, + "subsub": {Name: "subsub", CodePoints: []int{10965}, Characters: []byte{0xe2, 0xab, 0x95}}, + "subsup": {Name: "subsup", CodePoints: []int{10963}, Characters: []byte{0xe2, 0xab, 0x93}}, + "succ": {Name: "succ", CodePoints: []int{8827}, Characters: []byte{0xe2, 0x89, 0xbb}}, + "succapprox": {Name: "succapprox", CodePoints: []int{10936}, Characters: []byte{0xe2, 0xaa, 0xb8}}, + "succcurlyeq": {Name: "succcurlyeq", CodePoints: []int{8829}, Characters: []byte{0xe2, 0x89, 0xbd}}, + "succeq": {Name: "succeq", CodePoints: []int{10928}, Characters: []byte{0xe2, 0xaa, 0xb0}}, + "succnapprox": {Name: "succnapprox", CodePoints: []int{10938}, Characters: []byte{0xe2, 0xaa, 0xba}}, + "succneqq": {Name: "succneqq", CodePoints: []int{10934}, Characters: []byte{0xe2, 0xaa, 0xb6}}, + "succnsim": {Name: "succnsim", CodePoints: []int{8937}, Characters: []byte{0xe2, 0x8b, 0xa9}}, + "succsim": {Name: "succsim", CodePoints: []int{8831}, Characters: []byte{0xe2, 0x89, 0xbf}}, + "sum": {Name: "sum", CodePoints: []int{8721}, Characters: []byte{0xe2, 0x88, 0x91}}, + "sung": {Name: "sung", CodePoints: []int{9834}, Characters: []byte{0xe2, 0x99, 0xaa}}, + "sup": {Name: "sup", CodePoints: []int{8835}, Characters: []byte{0xe2, 0x8a, 0x83}}, + "sup1": {Name: "sup1", CodePoints: []int{185}, Characters: []byte{0xc2, 0xb9}}, + "sup2": {Name: "sup2", CodePoints: []int{178}, Characters: []byte{0xc2, 0xb2}}, + "sup3": {Name: "sup3", CodePoints: []int{179}, Characters: []byte{0xc2, 0xb3}}, + "supE": {Name: "supE", CodePoints: []int{10950}, Characters: []byte{0xe2, 0xab, 0x86}}, + "supdot": {Name: "supdot", CodePoints: []int{10942}, Characters: []byte{0xe2, 0xaa, 0xbe}}, + "supdsub": {Name: "supdsub", CodePoints: []int{10968}, Characters: []byte{0xe2, 0xab, 0x98}}, + "supe": {Name: "supe", CodePoints: []int{8839}, Characters: []byte{0xe2, 0x8a, 0x87}}, + "supedot": {Name: "supedot", CodePoints: []int{10948}, Characters: []byte{0xe2, 0xab, 0x84}}, + "suphsol": {Name: "suphsol", CodePoints: []int{10185}, Characters: []byte{0xe2, 0x9f, 0x89}}, + "suphsub": {Name: "suphsub", CodePoints: []int{10967}, Characters: []byte{0xe2, 0xab, 0x97}}, + "suplarr": {Name: "suplarr", CodePoints: []int{10619}, Characters: []byte{0xe2, 0xa5, 0xbb}}, + "supmult": {Name: "supmult", CodePoints: []int{10946}, Characters: []byte{0xe2, 0xab, 0x82}}, + "supnE": {Name: "supnE", CodePoints: []int{10956}, Characters: []byte{0xe2, 0xab, 0x8c}}, + "supne": {Name: "supne", CodePoints: []int{8843}, Characters: []byte{0xe2, 0x8a, 0x8b}}, + "supplus": {Name: "supplus", CodePoints: []int{10944}, Characters: []byte{0xe2, 0xab, 0x80}}, + "supset": {Name: "supset", CodePoints: []int{8835}, Characters: []byte{0xe2, 0x8a, 0x83}}, + "supseteq": {Name: "supseteq", CodePoints: []int{8839}, Characters: []byte{0xe2, 0x8a, 0x87}}, + "supseteqq": {Name: "supseteqq", CodePoints: []int{10950}, Characters: []byte{0xe2, 0xab, 0x86}}, + "supsetneq": {Name: "supsetneq", CodePoints: []int{8843}, Characters: []byte{0xe2, 0x8a, 0x8b}}, + "supsetneqq": {Name: "supsetneqq", CodePoints: []int{10956}, Characters: []byte{0xe2, 0xab, 0x8c}}, + "supsim": {Name: "supsim", CodePoints: []int{10952}, Characters: []byte{0xe2, 0xab, 0x88}}, + "supsub": {Name: "supsub", CodePoints: []int{10964}, Characters: []byte{0xe2, 0xab, 0x94}}, + "supsup": {Name: "supsup", CodePoints: []int{10966}, Characters: []byte{0xe2, 0xab, 0x96}}, + "swArr": {Name: "swArr", CodePoints: []int{8665}, Characters: []byte{0xe2, 0x87, 0x99}}, + "swarhk": {Name: "swarhk", CodePoints: []int{10534}, Characters: []byte{0xe2, 0xa4, 0xa6}}, + "swarr": {Name: "swarr", CodePoints: []int{8601}, Characters: []byte{0xe2, 0x86, 0x99}}, + "swarrow": {Name: "swarrow", CodePoints: []int{8601}, Characters: []byte{0xe2, 0x86, 0x99}}, + "swnwar": {Name: "swnwar", CodePoints: []int{10538}, Characters: []byte{0xe2, 0xa4, 0xaa}}, + "szlig": {Name: "szlig", CodePoints: []int{223}, Characters: []byte{0xc3, 0x9f}}, + "target": {Name: "target", CodePoints: []int{8982}, Characters: []byte{0xe2, 0x8c, 0x96}}, + "tau": {Name: "tau", CodePoints: []int{964}, Characters: []byte{0xcf, 0x84}}, + "tbrk": {Name: "tbrk", CodePoints: []int{9140}, Characters: []byte{0xe2, 0x8e, 0xb4}}, + "tcaron": {Name: "tcaron", CodePoints: []int{357}, Characters: []byte{0xc5, 0xa5}}, + "tcedil": {Name: "tcedil", CodePoints: []int{355}, Characters: []byte{0xc5, 0xa3}}, + "tcy": {Name: "tcy", CodePoints: []int{1090}, Characters: []byte{0xd1, 0x82}}, + "tdot": {Name: "tdot", CodePoints: []int{8411}, Characters: []byte{0xe2, 0x83, 0x9b}}, + "telrec": {Name: "telrec", CodePoints: []int{8981}, Characters: []byte{0xe2, 0x8c, 0x95}}, + "tfr": {Name: "tfr", CodePoints: []int{120113}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb1}}, + "there4": {Name: "there4", CodePoints: []int{8756}, Characters: []byte{0xe2, 0x88, 0xb4}}, + "therefore": {Name: "therefore", CodePoints: []int{8756}, Characters: []byte{0xe2, 0x88, 0xb4}}, + "theta": {Name: "theta", CodePoints: []int{952}, Characters: []byte{0xce, 0xb8}}, + "thetasym": {Name: "thetasym", CodePoints: []int{977}, Characters: []byte{0xcf, 0x91}}, + "thetav": {Name: "thetav", CodePoints: []int{977}, Characters: []byte{0xcf, 0x91}}, + "thickapprox": {Name: "thickapprox", CodePoints: []int{8776}, Characters: []byte{0xe2, 0x89, 0x88}}, + "thicksim": {Name: "thicksim", CodePoints: []int{8764}, Characters: []byte{0xe2, 0x88, 0xbc}}, + "thinsp": {Name: "thinsp", CodePoints: []int{8201}, Characters: []byte{0xe2, 0x80, 0x89}}, + "thkap": {Name: "thkap", CodePoints: []int{8776}, Characters: []byte{0xe2, 0x89, 0x88}}, + "thksim": {Name: "thksim", CodePoints: []int{8764}, Characters: []byte{0xe2, 0x88, 0xbc}}, + "thorn": {Name: "thorn", CodePoints: []int{254}, Characters: []byte{0xc3, 0xbe}}, + "tilde": {Name: "tilde", CodePoints: []int{732}, Characters: []byte{0xcb, 0x9c}}, + "times": {Name: "times", CodePoints: []int{215}, Characters: []byte{0xc3, 0x97}}, + "timesb": {Name: "timesb", CodePoints: []int{8864}, Characters: []byte{0xe2, 0x8a, 0xa0}}, + "timesbar": {Name: "timesbar", CodePoints: []int{10801}, Characters: []byte{0xe2, 0xa8, 0xb1}}, + "timesd": {Name: "timesd", CodePoints: []int{10800}, Characters: []byte{0xe2, 0xa8, 0xb0}}, + "tint": {Name: "tint", CodePoints: []int{8749}, Characters: []byte{0xe2, 0x88, 0xad}}, + "toea": {Name: "toea", CodePoints: []int{10536}, Characters: []byte{0xe2, 0xa4, 0xa8}}, + "top": {Name: "top", CodePoints: []int{8868}, Characters: []byte{0xe2, 0x8a, 0xa4}}, + "topbot": {Name: "topbot", CodePoints: []int{9014}, Characters: []byte{0xe2, 0x8c, 0xb6}}, + "topcir": {Name: "topcir", CodePoints: []int{10993}, Characters: []byte{0xe2, 0xab, 0xb1}}, + "topf": {Name: "topf", CodePoints: []int{120165}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa5}}, + "topfork": {Name: "topfork", CodePoints: []int{10970}, Characters: []byte{0xe2, 0xab, 0x9a}}, + "tosa": {Name: "tosa", CodePoints: []int{10537}, Characters: []byte{0xe2, 0xa4, 0xa9}}, + "tprime": {Name: "tprime", CodePoints: []int{8244}, Characters: []byte{0xe2, 0x80, 0xb4}}, + "trade": {Name: "trade", CodePoints: []int{8482}, Characters: []byte{0xe2, 0x84, 0xa2}}, + "triangle": {Name: "triangle", CodePoints: []int{9653}, Characters: []byte{0xe2, 0x96, 0xb5}}, + "triangledown": {Name: "triangledown", CodePoints: []int{9663}, Characters: []byte{0xe2, 0x96, 0xbf}}, + "triangleleft": {Name: "triangleleft", CodePoints: []int{9667}, Characters: []byte{0xe2, 0x97, 0x83}}, + "trianglelefteq": {Name: "trianglelefteq", CodePoints: []int{8884}, Characters: []byte{0xe2, 0x8a, 0xb4}}, + "triangleq": {Name: "triangleq", CodePoints: []int{8796}, Characters: []byte{0xe2, 0x89, 0x9c}}, + "triangleright": {Name: "triangleright", CodePoints: []int{9657}, Characters: []byte{0xe2, 0x96, 0xb9}}, + "trianglerighteq": {Name: "trianglerighteq", CodePoints: []int{8885}, Characters: []byte{0xe2, 0x8a, 0xb5}}, + "tridot": {Name: "tridot", CodePoints: []int{9708}, Characters: []byte{0xe2, 0x97, 0xac}}, + "trie": {Name: "trie", CodePoints: []int{8796}, Characters: []byte{0xe2, 0x89, 0x9c}}, + "triminus": {Name: "triminus", CodePoints: []int{10810}, Characters: []byte{0xe2, 0xa8, 0xba}}, + "triplus": {Name: "triplus", CodePoints: []int{10809}, Characters: []byte{0xe2, 0xa8, 0xb9}}, + "trisb": {Name: "trisb", CodePoints: []int{10701}, Characters: []byte{0xe2, 0xa7, 0x8d}}, + "tritime": {Name: "tritime", CodePoints: []int{10811}, Characters: []byte{0xe2, 0xa8, 0xbb}}, + "trpezium": {Name: "trpezium", CodePoints: []int{9186}, Characters: []byte{0xe2, 0x8f, 0xa2}}, + "tscr": {Name: "tscr", CodePoints: []int{120009}, Characters: []byte{0xf0, 0x9d, 0x93, 0x89}}, + "tscy": {Name: "tscy", CodePoints: []int{1094}, Characters: []byte{0xd1, 0x86}}, + "tshcy": {Name: "tshcy", CodePoints: []int{1115}, Characters: []byte{0xd1, 0x9b}}, + "tstrok": {Name: "tstrok", CodePoints: []int{359}, Characters: []byte{0xc5, 0xa7}}, + "twixt": {Name: "twixt", CodePoints: []int{8812}, Characters: []byte{0xe2, 0x89, 0xac}}, + "twoheadleftarrow": {Name: "twoheadleftarrow", CodePoints: []int{8606}, Characters: []byte{0xe2, 0x86, 0x9e}}, + "twoheadrightarrow": {Name: "twoheadrightarrow", CodePoints: []int{8608}, Characters: []byte{0xe2, 0x86, 0xa0}}, + "uArr": {Name: "uArr", CodePoints: []int{8657}, Characters: []byte{0xe2, 0x87, 0x91}}, + "uHar": {Name: "uHar", CodePoints: []int{10595}, Characters: []byte{0xe2, 0xa5, 0xa3}}, + "uacute": {Name: "uacute", CodePoints: []int{250}, Characters: []byte{0xc3, 0xba}}, + "uarr": {Name: "uarr", CodePoints: []int{8593}, Characters: []byte{0xe2, 0x86, 0x91}}, + "ubrcy": {Name: "ubrcy", CodePoints: []int{1118}, Characters: []byte{0xd1, 0x9e}}, + "ubreve": {Name: "ubreve", CodePoints: []int{365}, Characters: []byte{0xc5, 0xad}}, + "ucirc": {Name: "ucirc", CodePoints: []int{251}, Characters: []byte{0xc3, 0xbb}}, + "ucy": {Name: "ucy", CodePoints: []int{1091}, Characters: []byte{0xd1, 0x83}}, + "udarr": {Name: "udarr", CodePoints: []int{8645}, Characters: []byte{0xe2, 0x87, 0x85}}, + "udblac": {Name: "udblac", CodePoints: []int{369}, Characters: []byte{0xc5, 0xb1}}, + "udhar": {Name: "udhar", CodePoints: []int{10606}, Characters: []byte{0xe2, 0xa5, 0xae}}, + "ufisht": {Name: "ufisht", CodePoints: []int{10622}, Characters: []byte{0xe2, 0xa5, 0xbe}}, + "ufr": {Name: "ufr", CodePoints: []int{120114}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb2}}, + "ugrave": {Name: "ugrave", CodePoints: []int{249}, Characters: []byte{0xc3, 0xb9}}, + "uharl": {Name: "uharl", CodePoints: []int{8639}, Characters: []byte{0xe2, 0x86, 0xbf}}, + "uharr": {Name: "uharr", CodePoints: []int{8638}, Characters: []byte{0xe2, 0x86, 0xbe}}, + "uhblk": {Name: "uhblk", CodePoints: []int{9600}, Characters: []byte{0xe2, 0x96, 0x80}}, + "ulcorn": {Name: "ulcorn", CodePoints: []int{8988}, Characters: []byte{0xe2, 0x8c, 0x9c}}, + "ulcorner": {Name: "ulcorner", CodePoints: []int{8988}, Characters: []byte{0xe2, 0x8c, 0x9c}}, + "ulcrop": {Name: "ulcrop", CodePoints: []int{8975}, Characters: []byte{0xe2, 0x8c, 0x8f}}, + "ultri": {Name: "ultri", CodePoints: []int{9720}, Characters: []byte{0xe2, 0x97, 0xb8}}, + "umacr": {Name: "umacr", CodePoints: []int{363}, Characters: []byte{0xc5, 0xab}}, + "uml": {Name: "uml", CodePoints: []int{168}, Characters: []byte{0xc2, 0xa8}}, + "uogon": {Name: "uogon", CodePoints: []int{371}, Characters: []byte{0xc5, 0xb3}}, + "uopf": {Name: "uopf", CodePoints: []int{120166}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa6}}, + "uparrow": {Name: "uparrow", CodePoints: []int{8593}, Characters: []byte{0xe2, 0x86, 0x91}}, + "updownarrow": {Name: "updownarrow", CodePoints: []int{8597}, Characters: []byte{0xe2, 0x86, 0x95}}, + "upharpoonleft": {Name: "upharpoonleft", CodePoints: []int{8639}, Characters: []byte{0xe2, 0x86, 0xbf}}, + "upharpoonright": {Name: "upharpoonright", CodePoints: []int{8638}, Characters: []byte{0xe2, 0x86, 0xbe}}, + "uplus": {Name: "uplus", CodePoints: []int{8846}, Characters: []byte{0xe2, 0x8a, 0x8e}}, + "upsi": {Name: "upsi", CodePoints: []int{965}, Characters: []byte{0xcf, 0x85}}, + "upsih": {Name: "upsih", CodePoints: []int{978}, Characters: []byte{0xcf, 0x92}}, + "upsilon": {Name: "upsilon", CodePoints: []int{965}, Characters: []byte{0xcf, 0x85}}, + "upuparrows": {Name: "upuparrows", CodePoints: []int{8648}, Characters: []byte{0xe2, 0x87, 0x88}}, + "urcorn": {Name: "urcorn", CodePoints: []int{8989}, Characters: []byte{0xe2, 0x8c, 0x9d}}, + "urcorner": {Name: "urcorner", CodePoints: []int{8989}, Characters: []byte{0xe2, 0x8c, 0x9d}}, + "urcrop": {Name: "urcrop", CodePoints: []int{8974}, Characters: []byte{0xe2, 0x8c, 0x8e}}, + "uring": {Name: "uring", CodePoints: []int{367}, Characters: []byte{0xc5, 0xaf}}, + "urtri": {Name: "urtri", CodePoints: []int{9721}, Characters: []byte{0xe2, 0x97, 0xb9}}, + "uscr": {Name: "uscr", CodePoints: []int{120010}, Characters: []byte{0xf0, 0x9d, 0x93, 0x8a}}, + "utdot": {Name: "utdot", CodePoints: []int{8944}, Characters: []byte{0xe2, 0x8b, 0xb0}}, + "utilde": {Name: "utilde", CodePoints: []int{361}, Characters: []byte{0xc5, 0xa9}}, + "utri": {Name: "utri", CodePoints: []int{9653}, Characters: []byte{0xe2, 0x96, 0xb5}}, + "utrif": {Name: "utrif", CodePoints: []int{9652}, Characters: []byte{0xe2, 0x96, 0xb4}}, + "uuarr": {Name: "uuarr", CodePoints: []int{8648}, Characters: []byte{0xe2, 0x87, 0x88}}, + "uuml": {Name: "uuml", CodePoints: []int{252}, Characters: []byte{0xc3, 0xbc}}, + "uwangle": {Name: "uwangle", CodePoints: []int{10663}, Characters: []byte{0xe2, 0xa6, 0xa7}}, + "vArr": {Name: "vArr", CodePoints: []int{8661}, Characters: []byte{0xe2, 0x87, 0x95}}, + "vBar": {Name: "vBar", CodePoints: []int{10984}, Characters: []byte{0xe2, 0xab, 0xa8}}, + "vBarv": {Name: "vBarv", CodePoints: []int{10985}, Characters: []byte{0xe2, 0xab, 0xa9}}, + "vDash": {Name: "vDash", CodePoints: []int{8872}, Characters: []byte{0xe2, 0x8a, 0xa8}}, + "vangrt": {Name: "vangrt", CodePoints: []int{10652}, Characters: []byte{0xe2, 0xa6, 0x9c}}, + "varepsilon": {Name: "varepsilon", CodePoints: []int{1013}, Characters: []byte{0xcf, 0xb5}}, + "varkappa": {Name: "varkappa", CodePoints: []int{1008}, Characters: []byte{0xcf, 0xb0}}, + "varnothing": {Name: "varnothing", CodePoints: []int{8709}, Characters: []byte{0xe2, 0x88, 0x85}}, + "varphi": {Name: "varphi", CodePoints: []int{981}, Characters: []byte{0xcf, 0x95}}, + "varpi": {Name: "varpi", CodePoints: []int{982}, Characters: []byte{0xcf, 0x96}}, + "varpropto": {Name: "varpropto", CodePoints: []int{8733}, Characters: []byte{0xe2, 0x88, 0x9d}}, + "varr": {Name: "varr", CodePoints: []int{8597}, Characters: []byte{0xe2, 0x86, 0x95}}, + "varrho": {Name: "varrho", CodePoints: []int{1009}, Characters: []byte{0xcf, 0xb1}}, + "varsigma": {Name: "varsigma", CodePoints: []int{962}, Characters: []byte{0xcf, 0x82}}, + "varsubsetneq": {Name: "varsubsetneq", CodePoints: []int{8842, 65024}, Characters: []byte{0xe2, 0x8a, 0x8a, 0xef, 0xb8, 0x80}}, + "varsubsetneqq": {Name: "varsubsetneqq", CodePoints: []int{10955, 65024}, Characters: []byte{0xe2, 0xab, 0x8b, 0xef, 0xb8, 0x80}}, + "varsupsetneq": {Name: "varsupsetneq", CodePoints: []int{8843, 65024}, Characters: []byte{0xe2, 0x8a, 0x8b, 0xef, 0xb8, 0x80}}, + "varsupsetneqq": {Name: "varsupsetneqq", CodePoints: []int{10956, 65024}, Characters: []byte{0xe2, 0xab, 0x8c, 0xef, 0xb8, 0x80}}, + "vartheta": {Name: "vartheta", CodePoints: []int{977}, Characters: []byte{0xcf, 0x91}}, + "vartriangleleft": {Name: "vartriangleleft", CodePoints: []int{8882}, Characters: []byte{0xe2, 0x8a, 0xb2}}, + "vartriangleright": {Name: "vartriangleright", CodePoints: []int{8883}, Characters: []byte{0xe2, 0x8a, 0xb3}}, + "vcy": {Name: "vcy", CodePoints: []int{1074}, Characters: []byte{0xd0, 0xb2}}, + "vdash": {Name: "vdash", CodePoints: []int{8866}, Characters: []byte{0xe2, 0x8a, 0xa2}}, + "vee": {Name: "vee", CodePoints: []int{8744}, Characters: []byte{0xe2, 0x88, 0xa8}}, + "veebar": {Name: "veebar", CodePoints: []int{8891}, Characters: []byte{0xe2, 0x8a, 0xbb}}, + "veeeq": {Name: "veeeq", CodePoints: []int{8794}, Characters: []byte{0xe2, 0x89, 0x9a}}, + "vellip": {Name: "vellip", CodePoints: []int{8942}, Characters: []byte{0xe2, 0x8b, 0xae}}, + "verbar": {Name: "verbar", CodePoints: []int{124}, Characters: []byte{0x7c}}, + "vert": {Name: "vert", CodePoints: []int{124}, Characters: []byte{0x7c}}, + "vfr": {Name: "vfr", CodePoints: []int{120115}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb3}}, + "vltri": {Name: "vltri", CodePoints: []int{8882}, Characters: []byte{0xe2, 0x8a, 0xb2}}, + "vnsub": {Name: "vnsub", CodePoints: []int{8834, 8402}, Characters: []byte{0xe2, 0x8a, 0x82, 0xe2, 0x83, 0x92}}, + "vnsup": {Name: "vnsup", CodePoints: []int{8835, 8402}, Characters: []byte{0xe2, 0x8a, 0x83, 0xe2, 0x83, 0x92}}, + "vopf": {Name: "vopf", CodePoints: []int{120167}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa7}}, + "vprop": {Name: "vprop", CodePoints: []int{8733}, Characters: []byte{0xe2, 0x88, 0x9d}}, + "vrtri": {Name: "vrtri", CodePoints: []int{8883}, Characters: []byte{0xe2, 0x8a, 0xb3}}, + "vscr": {Name: "vscr", CodePoints: []int{120011}, Characters: []byte{0xf0, 0x9d, 0x93, 0x8b}}, + "vsubnE": {Name: "vsubnE", CodePoints: []int{10955, 65024}, Characters: []byte{0xe2, 0xab, 0x8b, 0xef, 0xb8, 0x80}}, + "vsubne": {Name: "vsubne", CodePoints: []int{8842, 65024}, Characters: []byte{0xe2, 0x8a, 0x8a, 0xef, 0xb8, 0x80}}, + "vsupnE": {Name: "vsupnE", CodePoints: []int{10956, 65024}, Characters: []byte{0xe2, 0xab, 0x8c, 0xef, 0xb8, 0x80}}, + "vsupne": {Name: "vsupne", CodePoints: []int{8843, 65024}, Characters: []byte{0xe2, 0x8a, 0x8b, 0xef, 0xb8, 0x80}}, + "vzigzag": {Name: "vzigzag", CodePoints: []int{10650}, Characters: []byte{0xe2, 0xa6, 0x9a}}, + "wcirc": {Name: "wcirc", CodePoints: []int{373}, Characters: []byte{0xc5, 0xb5}}, + "wedbar": {Name: "wedbar", CodePoints: []int{10847}, Characters: []byte{0xe2, 0xa9, 0x9f}}, + "wedge": {Name: "wedge", CodePoints: []int{8743}, Characters: []byte{0xe2, 0x88, 0xa7}}, + "wedgeq": {Name: "wedgeq", CodePoints: []int{8793}, Characters: []byte{0xe2, 0x89, 0x99}}, + "weierp": {Name: "weierp", CodePoints: []int{8472}, Characters: []byte{0xe2, 0x84, 0x98}}, + "wfr": {Name: "wfr", CodePoints: []int{120116}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb4}}, + "wopf": {Name: "wopf", CodePoints: []int{120168}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa8}}, + "wp": {Name: "wp", CodePoints: []int{8472}, Characters: []byte{0xe2, 0x84, 0x98}}, + "wr": {Name: "wr", CodePoints: []int{8768}, Characters: []byte{0xe2, 0x89, 0x80}}, + "wreath": {Name: "wreath", CodePoints: []int{8768}, Characters: []byte{0xe2, 0x89, 0x80}}, + "wscr": {Name: "wscr", CodePoints: []int{120012}, Characters: []byte{0xf0, 0x9d, 0x93, 0x8c}}, + "xcap": {Name: "xcap", CodePoints: []int{8898}, Characters: []byte{0xe2, 0x8b, 0x82}}, + "xcirc": {Name: "xcirc", CodePoints: []int{9711}, Characters: []byte{0xe2, 0x97, 0xaf}}, + "xcup": {Name: "xcup", CodePoints: []int{8899}, Characters: []byte{0xe2, 0x8b, 0x83}}, + "xdtri": {Name: "xdtri", CodePoints: []int{9661}, Characters: []byte{0xe2, 0x96, 0xbd}}, + "xfr": {Name: "xfr", CodePoints: []int{120117}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb5}}, + "xhArr": {Name: "xhArr", CodePoints: []int{10234}, Characters: []byte{0xe2, 0x9f, 0xba}}, + "xharr": {Name: "xharr", CodePoints: []int{10231}, Characters: []byte{0xe2, 0x9f, 0xb7}}, + "xi": {Name: "xi", CodePoints: []int{958}, Characters: []byte{0xce, 0xbe}}, + "xlArr": {Name: "xlArr", CodePoints: []int{10232}, Characters: []byte{0xe2, 0x9f, 0xb8}}, + "xlarr": {Name: "xlarr", CodePoints: []int{10229}, Characters: []byte{0xe2, 0x9f, 0xb5}}, + "xmap": {Name: "xmap", CodePoints: []int{10236}, Characters: []byte{0xe2, 0x9f, 0xbc}}, + "xnis": {Name: "xnis", CodePoints: []int{8955}, Characters: []byte{0xe2, 0x8b, 0xbb}}, + "xodot": {Name: "xodot", CodePoints: []int{10752}, Characters: []byte{0xe2, 0xa8, 0x80}}, + "xopf": {Name: "xopf", CodePoints: []int{120169}, Characters: []byte{0xf0, 0x9d, 0x95, 0xa9}}, + "xoplus": {Name: "xoplus", CodePoints: []int{10753}, Characters: []byte{0xe2, 0xa8, 0x81}}, + "xotime": {Name: "xotime", CodePoints: []int{10754}, Characters: []byte{0xe2, 0xa8, 0x82}}, + "xrArr": {Name: "xrArr", CodePoints: []int{10233}, Characters: []byte{0xe2, 0x9f, 0xb9}}, + "xrarr": {Name: "xrarr", CodePoints: []int{10230}, Characters: []byte{0xe2, 0x9f, 0xb6}}, + "xscr": {Name: "xscr", CodePoints: []int{120013}, Characters: []byte{0xf0, 0x9d, 0x93, 0x8d}}, + "xsqcup": {Name: "xsqcup", CodePoints: []int{10758}, Characters: []byte{0xe2, 0xa8, 0x86}}, + "xuplus": {Name: "xuplus", CodePoints: []int{10756}, Characters: []byte{0xe2, 0xa8, 0x84}}, + "xutri": {Name: "xutri", CodePoints: []int{9651}, Characters: []byte{0xe2, 0x96, 0xb3}}, + "xvee": {Name: "xvee", CodePoints: []int{8897}, Characters: []byte{0xe2, 0x8b, 0x81}}, + "xwedge": {Name: "xwedge", CodePoints: []int{8896}, Characters: []byte{0xe2, 0x8b, 0x80}}, + "yacute": {Name: "yacute", CodePoints: []int{253}, Characters: []byte{0xc3, 0xbd}}, + "yacy": {Name: "yacy", CodePoints: []int{1103}, Characters: []byte{0xd1, 0x8f}}, + "ycirc": {Name: "ycirc", CodePoints: []int{375}, Characters: []byte{0xc5, 0xb7}}, + "ycy": {Name: "ycy", CodePoints: []int{1099}, Characters: []byte{0xd1, 0x8b}}, + "yen": {Name: "yen", CodePoints: []int{165}, Characters: []byte{0xc2, 0xa5}}, + "yfr": {Name: "yfr", CodePoints: []int{120118}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb6}}, + "yicy": {Name: "yicy", CodePoints: []int{1111}, Characters: []byte{0xd1, 0x97}}, + "yopf": {Name: "yopf", CodePoints: []int{120170}, Characters: []byte{0xf0, 0x9d, 0x95, 0xaa}}, + "yscr": {Name: "yscr", CodePoints: []int{120014}, Characters: []byte{0xf0, 0x9d, 0x93, 0x8e}}, + "yucy": {Name: "yucy", CodePoints: []int{1102}, Characters: []byte{0xd1, 0x8e}}, + "yuml": {Name: "yuml", CodePoints: []int{255}, Characters: []byte{0xc3, 0xbf}}, + "zacute": {Name: "zacute", CodePoints: []int{378}, Characters: []byte{0xc5, 0xba}}, + "zcaron": {Name: "zcaron", CodePoints: []int{382}, Characters: []byte{0xc5, 0xbe}}, + "zcy": {Name: "zcy", CodePoints: []int{1079}, Characters: []byte{0xd0, 0xb7}}, + "zdot": {Name: "zdot", CodePoints: []int{380}, Characters: []byte{0xc5, 0xbc}}, + "zeetrf": {Name: "zeetrf", CodePoints: []int{8488}, Characters: []byte{0xe2, 0x84, 0xa8}}, + "zeta": {Name: "zeta", CodePoints: []int{950}, Characters: []byte{0xce, 0xb6}}, + "zfr": {Name: "zfr", CodePoints: []int{120119}, Characters: []byte{0xf0, 0x9d, 0x94, 0xb7}}, + "zhcy": {Name: "zhcy", CodePoints: []int{1078}, Characters: []byte{0xd0, 0xb6}}, + "zigrarr": {Name: "zigrarr", CodePoints: []int{8669}, Characters: []byte{0xe2, 0x87, 0x9d}}, + "zopf": {Name: "zopf", CodePoints: []int{120171}, Characters: []byte{0xf0, 0x9d, 0x95, 0xab}}, + "zscr": {Name: "zscr", CodePoints: []int{120015}, Characters: []byte{0xf0, 0x9d, 0x93, 0x8f}}, + "zwj": {Name: "zwj", CodePoints: []int{8205}, Characters: []byte{0xe2, 0x80, 0x8d}}, + "zwnj": {Name: "zwnj", CodePoints: []int{8204}, Characters: []byte{0xe2, 0x80, 0x8c}}, +} diff --git a/vendor/github.com/yuin/goldmark/util/unicode_case_folding.go b/vendor/github.com/yuin/goldmark/util/unicode_case_folding.go new file mode 100644 index 0000000000..f66ee7c43e --- /dev/null +++ b/vendor/github.com/yuin/goldmark/util/unicode_case_folding.go @@ -0,0 +1,1491 @@ +package util + +var unicodeCaseFoldings = map[rune][]rune{ + 0x41: []int32{97}, + 0x42: []int32{98}, + 0x43: []int32{99}, + 0x44: []int32{100}, + 0x45: []int32{101}, + 0x46: []int32{102}, + 0x47: []int32{103}, + 0x48: []int32{104}, + 0x49: []int32{105}, + 0x4a: []int32{106}, + 0x4b: []int32{107}, + 0x4c: []int32{108}, + 0x4d: []int32{109}, + 0x4e: []int32{110}, + 0x4f: []int32{111}, + 0x50: []int32{112}, + 0x51: []int32{113}, + 0x52: []int32{114}, + 0x53: []int32{115}, + 0x54: []int32{116}, + 0x55: []int32{117}, + 0x56: []int32{118}, + 0x57: []int32{119}, + 0x58: []int32{120}, + 0x59: []int32{121}, + 0x5a: []int32{122}, + 0xb5: []int32{956}, + 0xc0: []int32{224}, + 0xc1: []int32{225}, + 0xc2: []int32{226}, + 0xc3: []int32{227}, + 0xc4: []int32{228}, + 0xc5: []int32{229}, + 0xc6: []int32{230}, + 0xc7: []int32{231}, + 0xc8: []int32{232}, + 0xc9: []int32{233}, + 0xca: []int32{234}, + 0xcb: []int32{235}, + 0xcc: []int32{236}, + 0xcd: []int32{237}, + 0xce: []int32{238}, + 0xcf: []int32{239}, + 0xd0: []int32{240}, + 0xd1: []int32{241}, + 0xd2: []int32{242}, + 0xd3: []int32{243}, + 0xd4: []int32{244}, + 0xd5: []int32{245}, + 0xd6: []int32{246}, + 0xd8: []int32{248}, + 0xd9: []int32{249}, + 0xda: []int32{250}, + 0xdb: []int32{251}, + 0xdc: []int32{252}, + 0xdd: []int32{253}, + 0xde: []int32{254}, + 0xdf: []int32{115, 115}, + 0x100: []int32{257}, + 0x102: []int32{259}, + 0x104: []int32{261}, + 0x106: []int32{263}, + 0x108: []int32{265}, + 0x10a: []int32{267}, + 0x10c: []int32{269}, + 0x10e: []int32{271}, + 0x110: []int32{273}, + 0x112: []int32{275}, + 0x114: []int32{277}, + 0x116: []int32{279}, + 0x118: []int32{281}, + 0x11a: []int32{283}, + 0x11c: []int32{285}, + 0x11e: []int32{287}, + 0x120: []int32{289}, + 0x122: []int32{291}, + 0x124: []int32{293}, + 0x126: []int32{295}, + 0x128: []int32{297}, + 0x12a: []int32{299}, + 0x12c: []int32{301}, + 0x12e: []int32{303}, + 0x130: []int32{105, 775}, + 0x132: []int32{307}, + 0x134: []int32{309}, + 0x136: []int32{311}, + 0x139: []int32{314}, + 0x13b: []int32{316}, + 0x13d: []int32{318}, + 0x13f: []int32{320}, + 0x141: []int32{322}, + 0x143: []int32{324}, + 0x145: []int32{326}, + 0x147: []int32{328}, + 0x149: []int32{700, 110}, + 0x14a: []int32{331}, + 0x14c: []int32{333}, + 0x14e: []int32{335}, + 0x150: []int32{337}, + 0x152: []int32{339}, + 0x154: []int32{341}, + 0x156: []int32{343}, + 0x158: []int32{345}, + 0x15a: []int32{347}, + 0x15c: []int32{349}, + 0x15e: []int32{351}, + 0x160: []int32{353}, + 0x162: []int32{355}, + 0x164: []int32{357}, + 0x166: []int32{359}, + 0x168: []int32{361}, + 0x16a: []int32{363}, + 0x16c: []int32{365}, + 0x16e: []int32{367}, + 0x170: []int32{369}, + 0x172: []int32{371}, + 0x174: []int32{373}, + 0x176: []int32{375}, + 0x178: []int32{255}, + 0x179: []int32{378}, + 0x17b: []int32{380}, + 0x17d: []int32{382}, + 0x17f: []int32{115}, + 0x181: []int32{595}, + 0x182: []int32{387}, + 0x184: []int32{389}, + 0x186: []int32{596}, + 0x187: []int32{392}, + 0x189: []int32{598}, + 0x18a: []int32{599}, + 0x18b: []int32{396}, + 0x18e: []int32{477}, + 0x18f: []int32{601}, + 0x190: []int32{603}, + 0x191: []int32{402}, + 0x193: []int32{608}, + 0x194: []int32{611}, + 0x196: []int32{617}, + 0x197: []int32{616}, + 0x198: []int32{409}, + 0x19c: []int32{623}, + 0x19d: []int32{626}, + 0x19f: []int32{629}, + 0x1a0: []int32{417}, + 0x1a2: []int32{419}, + 0x1a4: []int32{421}, + 0x1a6: []int32{640}, + 0x1a7: []int32{424}, + 0x1a9: []int32{643}, + 0x1ac: []int32{429}, + 0x1ae: []int32{648}, + 0x1af: []int32{432}, + 0x1b1: []int32{650}, + 0x1b2: []int32{651}, + 0x1b3: []int32{436}, + 0x1b5: []int32{438}, + 0x1b7: []int32{658}, + 0x1b8: []int32{441}, + 0x1bc: []int32{445}, + 0x1c4: []int32{454}, + 0x1c5: []int32{454}, + 0x1c7: []int32{457}, + 0x1c8: []int32{457}, + 0x1ca: []int32{460}, + 0x1cb: []int32{460}, + 0x1cd: []int32{462}, + 0x1cf: []int32{464}, + 0x1d1: []int32{466}, + 0x1d3: []int32{468}, + 0x1d5: []int32{470}, + 0x1d7: []int32{472}, + 0x1d9: []int32{474}, + 0x1db: []int32{476}, + 0x1de: []int32{479}, + 0x1e0: []int32{481}, + 0x1e2: []int32{483}, + 0x1e4: []int32{485}, + 0x1e6: []int32{487}, + 0x1e8: []int32{489}, + 0x1ea: []int32{491}, + 0x1ec: []int32{493}, + 0x1ee: []int32{495}, + 0x1f0: []int32{106, 780}, + 0x1f1: []int32{499}, + 0x1f2: []int32{499}, + 0x1f4: []int32{501}, + 0x1f6: []int32{405}, + 0x1f7: []int32{447}, + 0x1f8: []int32{505}, + 0x1fa: []int32{507}, + 0x1fc: []int32{509}, + 0x1fe: []int32{511}, + 0x200: []int32{513}, + 0x202: []int32{515}, + 0x204: []int32{517}, + 0x206: []int32{519}, + 0x208: []int32{521}, + 0x20a: []int32{523}, + 0x20c: []int32{525}, + 0x20e: []int32{527}, + 0x210: []int32{529}, + 0x212: []int32{531}, + 0x214: []int32{533}, + 0x216: []int32{535}, + 0x218: []int32{537}, + 0x21a: []int32{539}, + 0x21c: []int32{541}, + 0x21e: []int32{543}, + 0x220: []int32{414}, + 0x222: []int32{547}, + 0x224: []int32{549}, + 0x226: []int32{551}, + 0x228: []int32{553}, + 0x22a: []int32{555}, + 0x22c: []int32{557}, + 0x22e: []int32{559}, + 0x230: []int32{561}, + 0x232: []int32{563}, + 0x23a: []int32{11365}, + 0x23b: []int32{572}, + 0x23d: []int32{410}, + 0x23e: []int32{11366}, + 0x241: []int32{578}, + 0x243: []int32{384}, + 0x244: []int32{649}, + 0x245: []int32{652}, + 0x246: []int32{583}, + 0x248: []int32{585}, + 0x24a: []int32{587}, + 0x24c: []int32{589}, + 0x24e: []int32{591}, + 0x345: []int32{953}, + 0x370: []int32{881}, + 0x372: []int32{883}, + 0x376: []int32{887}, + 0x37f: []int32{1011}, + 0x386: []int32{940}, + 0x388: []int32{941}, + 0x389: []int32{942}, + 0x38a: []int32{943}, + 0x38c: []int32{972}, + 0x38e: []int32{973}, + 0x38f: []int32{974}, + 0x390: []int32{953, 776, 769}, + 0x391: []int32{945}, + 0x392: []int32{946}, + 0x393: []int32{947}, + 0x394: []int32{948}, + 0x395: []int32{949}, + 0x396: []int32{950}, + 0x397: []int32{951}, + 0x398: []int32{952}, + 0x399: []int32{953}, + 0x39a: []int32{954}, + 0x39b: []int32{955}, + 0x39c: []int32{956}, + 0x39d: []int32{957}, + 0x39e: []int32{958}, + 0x39f: []int32{959}, + 0x3a0: []int32{960}, + 0x3a1: []int32{961}, + 0x3a3: []int32{963}, + 0x3a4: []int32{964}, + 0x3a5: []int32{965}, + 0x3a6: []int32{966}, + 0x3a7: []int32{967}, + 0x3a8: []int32{968}, + 0x3a9: []int32{969}, + 0x3aa: []int32{970}, + 0x3ab: []int32{971}, + 0x3b0: []int32{965, 776, 769}, + 0x3c2: []int32{963}, + 0x3cf: []int32{983}, + 0x3d0: []int32{946}, + 0x3d1: []int32{952}, + 0x3d5: []int32{966}, + 0x3d6: []int32{960}, + 0x3d8: []int32{985}, + 0x3da: []int32{987}, + 0x3dc: []int32{989}, + 0x3de: []int32{991}, + 0x3e0: []int32{993}, + 0x3e2: []int32{995}, + 0x3e4: []int32{997}, + 0x3e6: []int32{999}, + 0x3e8: []int32{1001}, + 0x3ea: []int32{1003}, + 0x3ec: []int32{1005}, + 0x3ee: []int32{1007}, + 0x3f0: []int32{954}, + 0x3f1: []int32{961}, + 0x3f4: []int32{952}, + 0x3f5: []int32{949}, + 0x3f7: []int32{1016}, + 0x3f9: []int32{1010}, + 0x3fa: []int32{1019}, + 0x3fd: []int32{891}, + 0x3fe: []int32{892}, + 0x3ff: []int32{893}, + 0x400: []int32{1104}, + 0x401: []int32{1105}, + 0x402: []int32{1106}, + 0x403: []int32{1107}, + 0x404: []int32{1108}, + 0x405: []int32{1109}, + 0x406: []int32{1110}, + 0x407: []int32{1111}, + 0x408: []int32{1112}, + 0x409: []int32{1113}, + 0x40a: []int32{1114}, + 0x40b: []int32{1115}, + 0x40c: []int32{1116}, + 0x40d: []int32{1117}, + 0x40e: []int32{1118}, + 0x40f: []int32{1119}, + 0x410: []int32{1072}, + 0x411: []int32{1073}, + 0x412: []int32{1074}, + 0x413: []int32{1075}, + 0x414: []int32{1076}, + 0x415: []int32{1077}, + 0x416: []int32{1078}, + 0x417: []int32{1079}, + 0x418: []int32{1080}, + 0x419: []int32{1081}, + 0x41a: []int32{1082}, + 0x41b: []int32{1083}, + 0x41c: []int32{1084}, + 0x41d: []int32{1085}, + 0x41e: []int32{1086}, + 0x41f: []int32{1087}, + 0x420: []int32{1088}, + 0x421: []int32{1089}, + 0x422: []int32{1090}, + 0x423: []int32{1091}, + 0x424: []int32{1092}, + 0x425: []int32{1093}, + 0x426: []int32{1094}, + 0x427: []int32{1095}, + 0x428: []int32{1096}, + 0x429: []int32{1097}, + 0x42a: []int32{1098}, + 0x42b: []int32{1099}, + 0x42c: []int32{1100}, + 0x42d: []int32{1101}, + 0x42e: []int32{1102}, + 0x42f: []int32{1103}, + 0x460: []int32{1121}, + 0x462: []int32{1123}, + 0x464: []int32{1125}, + 0x466: []int32{1127}, + 0x468: []int32{1129}, + 0x46a: []int32{1131}, + 0x46c: []int32{1133}, + 0x46e: []int32{1135}, + 0x470: []int32{1137}, + 0x472: []int32{1139}, + 0x474: []int32{1141}, + 0x476: []int32{1143}, + 0x478: []int32{1145}, + 0x47a: []int32{1147}, + 0x47c: []int32{1149}, + 0x47e: []int32{1151}, + 0x480: []int32{1153}, + 0x48a: []int32{1163}, + 0x48c: []int32{1165}, + 0x48e: []int32{1167}, + 0x490: []int32{1169}, + 0x492: []int32{1171}, + 0x494: []int32{1173}, + 0x496: []int32{1175}, + 0x498: []int32{1177}, + 0x49a: []int32{1179}, + 0x49c: []int32{1181}, + 0x49e: []int32{1183}, + 0x4a0: []int32{1185}, + 0x4a2: []int32{1187}, + 0x4a4: []int32{1189}, + 0x4a6: []int32{1191}, + 0x4a8: []int32{1193}, + 0x4aa: []int32{1195}, + 0x4ac: []int32{1197}, + 0x4ae: []int32{1199}, + 0x4b0: []int32{1201}, + 0x4b2: []int32{1203}, + 0x4b4: []int32{1205}, + 0x4b6: []int32{1207}, + 0x4b8: []int32{1209}, + 0x4ba: []int32{1211}, + 0x4bc: []int32{1213}, + 0x4be: []int32{1215}, + 0x4c0: []int32{1231}, + 0x4c1: []int32{1218}, + 0x4c3: []int32{1220}, + 0x4c5: []int32{1222}, + 0x4c7: []int32{1224}, + 0x4c9: []int32{1226}, + 0x4cb: []int32{1228}, + 0x4cd: []int32{1230}, + 0x4d0: []int32{1233}, + 0x4d2: []int32{1235}, + 0x4d4: []int32{1237}, + 0x4d6: []int32{1239}, + 0x4d8: []int32{1241}, + 0x4da: []int32{1243}, + 0x4dc: []int32{1245}, + 0x4de: []int32{1247}, + 0x4e0: []int32{1249}, + 0x4e2: []int32{1251}, + 0x4e4: []int32{1253}, + 0x4e6: []int32{1255}, + 0x4e8: []int32{1257}, + 0x4ea: []int32{1259}, + 0x4ec: []int32{1261}, + 0x4ee: []int32{1263}, + 0x4f0: []int32{1265}, + 0x4f2: []int32{1267}, + 0x4f4: []int32{1269}, + 0x4f6: []int32{1271}, + 0x4f8: []int32{1273}, + 0x4fa: []int32{1275}, + 0x4fc: []int32{1277}, + 0x4fe: []int32{1279}, + 0x500: []int32{1281}, + 0x502: []int32{1283}, + 0x504: []int32{1285}, + 0x506: []int32{1287}, + 0x508: []int32{1289}, + 0x50a: []int32{1291}, + 0x50c: []int32{1293}, + 0x50e: []int32{1295}, + 0x510: []int32{1297}, + 0x512: []int32{1299}, + 0x514: []int32{1301}, + 0x516: []int32{1303}, + 0x518: []int32{1305}, + 0x51a: []int32{1307}, + 0x51c: []int32{1309}, + 0x51e: []int32{1311}, + 0x520: []int32{1313}, + 0x522: []int32{1315}, + 0x524: []int32{1317}, + 0x526: []int32{1319}, + 0x528: []int32{1321}, + 0x52a: []int32{1323}, + 0x52c: []int32{1325}, + 0x52e: []int32{1327}, + 0x531: []int32{1377}, + 0x532: []int32{1378}, + 0x533: []int32{1379}, + 0x534: []int32{1380}, + 0x535: []int32{1381}, + 0x536: []int32{1382}, + 0x537: []int32{1383}, + 0x538: []int32{1384}, + 0x539: []int32{1385}, + 0x53a: []int32{1386}, + 0x53b: []int32{1387}, + 0x53c: []int32{1388}, + 0x53d: []int32{1389}, + 0x53e: []int32{1390}, + 0x53f: []int32{1391}, + 0x540: []int32{1392}, + 0x541: []int32{1393}, + 0x542: []int32{1394}, + 0x543: []int32{1395}, + 0x544: []int32{1396}, + 0x545: []int32{1397}, + 0x546: []int32{1398}, + 0x547: []int32{1399}, + 0x548: []int32{1400}, + 0x549: []int32{1401}, + 0x54a: []int32{1402}, + 0x54b: []int32{1403}, + 0x54c: []int32{1404}, + 0x54d: []int32{1405}, + 0x54e: []int32{1406}, + 0x54f: []int32{1407}, + 0x550: []int32{1408}, + 0x551: []int32{1409}, + 0x552: []int32{1410}, + 0x553: []int32{1411}, + 0x554: []int32{1412}, + 0x555: []int32{1413}, + 0x556: []int32{1414}, + 0x587: []int32{1381, 1410}, + 0x10a0: []int32{11520}, + 0x10a1: []int32{11521}, + 0x10a2: []int32{11522}, + 0x10a3: []int32{11523}, + 0x10a4: []int32{11524}, + 0x10a5: []int32{11525}, + 0x10a6: []int32{11526}, + 0x10a7: []int32{11527}, + 0x10a8: []int32{11528}, + 0x10a9: []int32{11529}, + 0x10aa: []int32{11530}, + 0x10ab: []int32{11531}, + 0x10ac: []int32{11532}, + 0x10ad: []int32{11533}, + 0x10ae: []int32{11534}, + 0x10af: []int32{11535}, + 0x10b0: []int32{11536}, + 0x10b1: []int32{11537}, + 0x10b2: []int32{11538}, + 0x10b3: []int32{11539}, + 0x10b4: []int32{11540}, + 0x10b5: []int32{11541}, + 0x10b6: []int32{11542}, + 0x10b7: []int32{11543}, + 0x10b8: []int32{11544}, + 0x10b9: []int32{11545}, + 0x10ba: []int32{11546}, + 0x10bb: []int32{11547}, + 0x10bc: []int32{11548}, + 0x10bd: []int32{11549}, + 0x10be: []int32{11550}, + 0x10bf: []int32{11551}, + 0x10c0: []int32{11552}, + 0x10c1: []int32{11553}, + 0x10c2: []int32{11554}, + 0x10c3: []int32{11555}, + 0x10c4: []int32{11556}, + 0x10c5: []int32{11557}, + 0x10c7: []int32{11559}, + 0x10cd: []int32{11565}, + 0x13f8: []int32{5104}, + 0x13f9: []int32{5105}, + 0x13fa: []int32{5106}, + 0x13fb: []int32{5107}, + 0x13fc: []int32{5108}, + 0x13fd: []int32{5109}, + 0x1c80: []int32{1074}, + 0x1c81: []int32{1076}, + 0x1c82: []int32{1086}, + 0x1c83: []int32{1089}, + 0x1c84: []int32{1090}, + 0x1c85: []int32{1090}, + 0x1c86: []int32{1098}, + 0x1c87: []int32{1123}, + 0x1c88: []int32{42571}, + 0x1c90: []int32{4304}, + 0x1c91: []int32{4305}, + 0x1c92: []int32{4306}, + 0x1c93: []int32{4307}, + 0x1c94: []int32{4308}, + 0x1c95: []int32{4309}, + 0x1c96: []int32{4310}, + 0x1c97: []int32{4311}, + 0x1c98: []int32{4312}, + 0x1c99: []int32{4313}, + 0x1c9a: []int32{4314}, + 0x1c9b: []int32{4315}, + 0x1c9c: []int32{4316}, + 0x1c9d: []int32{4317}, + 0x1c9e: []int32{4318}, + 0x1c9f: []int32{4319}, + 0x1ca0: []int32{4320}, + 0x1ca1: []int32{4321}, + 0x1ca2: []int32{4322}, + 0x1ca3: []int32{4323}, + 0x1ca4: []int32{4324}, + 0x1ca5: []int32{4325}, + 0x1ca6: []int32{4326}, + 0x1ca7: []int32{4327}, + 0x1ca8: []int32{4328}, + 0x1ca9: []int32{4329}, + 0x1caa: []int32{4330}, + 0x1cab: []int32{4331}, + 0x1cac: []int32{4332}, + 0x1cad: []int32{4333}, + 0x1cae: []int32{4334}, + 0x1caf: []int32{4335}, + 0x1cb0: []int32{4336}, + 0x1cb1: []int32{4337}, + 0x1cb2: []int32{4338}, + 0x1cb3: []int32{4339}, + 0x1cb4: []int32{4340}, + 0x1cb5: []int32{4341}, + 0x1cb6: []int32{4342}, + 0x1cb7: []int32{4343}, + 0x1cb8: []int32{4344}, + 0x1cb9: []int32{4345}, + 0x1cba: []int32{4346}, + 0x1cbd: []int32{4349}, + 0x1cbe: []int32{4350}, + 0x1cbf: []int32{4351}, + 0x1e00: []int32{7681}, + 0x1e02: []int32{7683}, + 0x1e04: []int32{7685}, + 0x1e06: []int32{7687}, + 0x1e08: []int32{7689}, + 0x1e0a: []int32{7691}, + 0x1e0c: []int32{7693}, + 0x1e0e: []int32{7695}, + 0x1e10: []int32{7697}, + 0x1e12: []int32{7699}, + 0x1e14: []int32{7701}, + 0x1e16: []int32{7703}, + 0x1e18: []int32{7705}, + 0x1e1a: []int32{7707}, + 0x1e1c: []int32{7709}, + 0x1e1e: []int32{7711}, + 0x1e20: []int32{7713}, + 0x1e22: []int32{7715}, + 0x1e24: []int32{7717}, + 0x1e26: []int32{7719}, + 0x1e28: []int32{7721}, + 0x1e2a: []int32{7723}, + 0x1e2c: []int32{7725}, + 0x1e2e: []int32{7727}, + 0x1e30: []int32{7729}, + 0x1e32: []int32{7731}, + 0x1e34: []int32{7733}, + 0x1e36: []int32{7735}, + 0x1e38: []int32{7737}, + 0x1e3a: []int32{7739}, + 0x1e3c: []int32{7741}, + 0x1e3e: []int32{7743}, + 0x1e40: []int32{7745}, + 0x1e42: []int32{7747}, + 0x1e44: []int32{7749}, + 0x1e46: []int32{7751}, + 0x1e48: []int32{7753}, + 0x1e4a: []int32{7755}, + 0x1e4c: []int32{7757}, + 0x1e4e: []int32{7759}, + 0x1e50: []int32{7761}, + 0x1e52: []int32{7763}, + 0x1e54: []int32{7765}, + 0x1e56: []int32{7767}, + 0x1e58: []int32{7769}, + 0x1e5a: []int32{7771}, + 0x1e5c: []int32{7773}, + 0x1e5e: []int32{7775}, + 0x1e60: []int32{7777}, + 0x1e62: []int32{7779}, + 0x1e64: []int32{7781}, + 0x1e66: []int32{7783}, + 0x1e68: []int32{7785}, + 0x1e6a: []int32{7787}, + 0x1e6c: []int32{7789}, + 0x1e6e: []int32{7791}, + 0x1e70: []int32{7793}, + 0x1e72: []int32{7795}, + 0x1e74: []int32{7797}, + 0x1e76: []int32{7799}, + 0x1e78: []int32{7801}, + 0x1e7a: []int32{7803}, + 0x1e7c: []int32{7805}, + 0x1e7e: []int32{7807}, + 0x1e80: []int32{7809}, + 0x1e82: []int32{7811}, + 0x1e84: []int32{7813}, + 0x1e86: []int32{7815}, + 0x1e88: []int32{7817}, + 0x1e8a: []int32{7819}, + 0x1e8c: []int32{7821}, + 0x1e8e: []int32{7823}, + 0x1e90: []int32{7825}, + 0x1e92: []int32{7827}, + 0x1e94: []int32{7829}, + 0x1e96: []int32{104, 817}, + 0x1e97: []int32{116, 776}, + 0x1e98: []int32{119, 778}, + 0x1e99: []int32{121, 778}, + 0x1e9a: []int32{97, 702}, + 0x1e9b: []int32{7777}, + 0x1e9e: []int32{115, 115}, + 0x1ea0: []int32{7841}, + 0x1ea2: []int32{7843}, + 0x1ea4: []int32{7845}, + 0x1ea6: []int32{7847}, + 0x1ea8: []int32{7849}, + 0x1eaa: []int32{7851}, + 0x1eac: []int32{7853}, + 0x1eae: []int32{7855}, + 0x1eb0: []int32{7857}, + 0x1eb2: []int32{7859}, + 0x1eb4: []int32{7861}, + 0x1eb6: []int32{7863}, + 0x1eb8: []int32{7865}, + 0x1eba: []int32{7867}, + 0x1ebc: []int32{7869}, + 0x1ebe: []int32{7871}, + 0x1ec0: []int32{7873}, + 0x1ec2: []int32{7875}, + 0x1ec4: []int32{7877}, + 0x1ec6: []int32{7879}, + 0x1ec8: []int32{7881}, + 0x1eca: []int32{7883}, + 0x1ecc: []int32{7885}, + 0x1ece: []int32{7887}, + 0x1ed0: []int32{7889}, + 0x1ed2: []int32{7891}, + 0x1ed4: []int32{7893}, + 0x1ed6: []int32{7895}, + 0x1ed8: []int32{7897}, + 0x1eda: []int32{7899}, + 0x1edc: []int32{7901}, + 0x1ede: []int32{7903}, + 0x1ee0: []int32{7905}, + 0x1ee2: []int32{7907}, + 0x1ee4: []int32{7909}, + 0x1ee6: []int32{7911}, + 0x1ee8: []int32{7913}, + 0x1eea: []int32{7915}, + 0x1eec: []int32{7917}, + 0x1eee: []int32{7919}, + 0x1ef0: []int32{7921}, + 0x1ef2: []int32{7923}, + 0x1ef4: []int32{7925}, + 0x1ef6: []int32{7927}, + 0x1ef8: []int32{7929}, + 0x1efa: []int32{7931}, + 0x1efc: []int32{7933}, + 0x1efe: []int32{7935}, + 0x1f08: []int32{7936}, + 0x1f09: []int32{7937}, + 0x1f0a: []int32{7938}, + 0x1f0b: []int32{7939}, + 0x1f0c: []int32{7940}, + 0x1f0d: []int32{7941}, + 0x1f0e: []int32{7942}, + 0x1f0f: []int32{7943}, + 0x1f18: []int32{7952}, + 0x1f19: []int32{7953}, + 0x1f1a: []int32{7954}, + 0x1f1b: []int32{7955}, + 0x1f1c: []int32{7956}, + 0x1f1d: []int32{7957}, + 0x1f28: []int32{7968}, + 0x1f29: []int32{7969}, + 0x1f2a: []int32{7970}, + 0x1f2b: []int32{7971}, + 0x1f2c: []int32{7972}, + 0x1f2d: []int32{7973}, + 0x1f2e: []int32{7974}, + 0x1f2f: []int32{7975}, + 0x1f38: []int32{7984}, + 0x1f39: []int32{7985}, + 0x1f3a: []int32{7986}, + 0x1f3b: []int32{7987}, + 0x1f3c: []int32{7988}, + 0x1f3d: []int32{7989}, + 0x1f3e: []int32{7990}, + 0x1f3f: []int32{7991}, + 0x1f48: []int32{8000}, + 0x1f49: []int32{8001}, + 0x1f4a: []int32{8002}, + 0x1f4b: []int32{8003}, + 0x1f4c: []int32{8004}, + 0x1f4d: []int32{8005}, + 0x1f50: []int32{965, 787}, + 0x1f52: []int32{965, 787, 768}, + 0x1f54: []int32{965, 787, 769}, + 0x1f56: []int32{965, 787, 834}, + 0x1f59: []int32{8017}, + 0x1f5b: []int32{8019}, + 0x1f5d: []int32{8021}, + 0x1f5f: []int32{8023}, + 0x1f68: []int32{8032}, + 0x1f69: []int32{8033}, + 0x1f6a: []int32{8034}, + 0x1f6b: []int32{8035}, + 0x1f6c: []int32{8036}, + 0x1f6d: []int32{8037}, + 0x1f6e: []int32{8038}, + 0x1f6f: []int32{8039}, + 0x1f80: []int32{7936, 953}, + 0x1f81: []int32{7937, 953}, + 0x1f82: []int32{7938, 953}, + 0x1f83: []int32{7939, 953}, + 0x1f84: []int32{7940, 953}, + 0x1f85: []int32{7941, 953}, + 0x1f86: []int32{7942, 953}, + 0x1f87: []int32{7943, 953}, + 0x1f88: []int32{7936, 953}, + 0x1f89: []int32{7937, 953}, + 0x1f8a: []int32{7938, 953}, + 0x1f8b: []int32{7939, 953}, + 0x1f8c: []int32{7940, 953}, + 0x1f8d: []int32{7941, 953}, + 0x1f8e: []int32{7942, 953}, + 0x1f8f: []int32{7943, 953}, + 0x1f90: []int32{7968, 953}, + 0x1f91: []int32{7969, 953}, + 0x1f92: []int32{7970, 953}, + 0x1f93: []int32{7971, 953}, + 0x1f94: []int32{7972, 953}, + 0x1f95: []int32{7973, 953}, + 0x1f96: []int32{7974, 953}, + 0x1f97: []int32{7975, 953}, + 0x1f98: []int32{7968, 953}, + 0x1f99: []int32{7969, 953}, + 0x1f9a: []int32{7970, 953}, + 0x1f9b: []int32{7971, 953}, + 0x1f9c: []int32{7972, 953}, + 0x1f9d: []int32{7973, 953}, + 0x1f9e: []int32{7974, 953}, + 0x1f9f: []int32{7975, 953}, + 0x1fa0: []int32{8032, 953}, + 0x1fa1: []int32{8033, 953}, + 0x1fa2: []int32{8034, 953}, + 0x1fa3: []int32{8035, 953}, + 0x1fa4: []int32{8036, 953}, + 0x1fa5: []int32{8037, 953}, + 0x1fa6: []int32{8038, 953}, + 0x1fa7: []int32{8039, 953}, + 0x1fa8: []int32{8032, 953}, + 0x1fa9: []int32{8033, 953}, + 0x1faa: []int32{8034, 953}, + 0x1fab: []int32{8035, 953}, + 0x1fac: []int32{8036, 953}, + 0x1fad: []int32{8037, 953}, + 0x1fae: []int32{8038, 953}, + 0x1faf: []int32{8039, 953}, + 0x1fb2: []int32{8048, 953}, + 0x1fb3: []int32{945, 953}, + 0x1fb4: []int32{940, 953}, + 0x1fb6: []int32{945, 834}, + 0x1fb7: []int32{945, 834, 953}, + 0x1fb8: []int32{8112}, + 0x1fb9: []int32{8113}, + 0x1fba: []int32{8048}, + 0x1fbb: []int32{8049}, + 0x1fbc: []int32{945, 953}, + 0x1fbe: []int32{953}, + 0x1fc2: []int32{8052, 953}, + 0x1fc3: []int32{951, 953}, + 0x1fc4: []int32{942, 953}, + 0x1fc6: []int32{951, 834}, + 0x1fc7: []int32{951, 834, 953}, + 0x1fc8: []int32{8050}, + 0x1fc9: []int32{8051}, + 0x1fca: []int32{8052}, + 0x1fcb: []int32{8053}, + 0x1fcc: []int32{951, 953}, + 0x1fd2: []int32{953, 776, 768}, + 0x1fd3: []int32{953, 776, 769}, + 0x1fd6: []int32{953, 834}, + 0x1fd7: []int32{953, 776, 834}, + 0x1fd8: []int32{8144}, + 0x1fd9: []int32{8145}, + 0x1fda: []int32{8054}, + 0x1fdb: []int32{8055}, + 0x1fe2: []int32{965, 776, 768}, + 0x1fe3: []int32{965, 776, 769}, + 0x1fe4: []int32{961, 787}, + 0x1fe6: []int32{965, 834}, + 0x1fe7: []int32{965, 776, 834}, + 0x1fe8: []int32{8160}, + 0x1fe9: []int32{8161}, + 0x1fea: []int32{8058}, + 0x1feb: []int32{8059}, + 0x1fec: []int32{8165}, + 0x1ff2: []int32{8060, 953}, + 0x1ff3: []int32{969, 953}, + 0x1ff4: []int32{974, 953}, + 0x1ff6: []int32{969, 834}, + 0x1ff7: []int32{969, 834, 953}, + 0x1ff8: []int32{8056}, + 0x1ff9: []int32{8057}, + 0x1ffa: []int32{8060}, + 0x1ffb: []int32{8061}, + 0x1ffc: []int32{969, 953}, + 0x2126: []int32{969}, + 0x212a: []int32{107}, + 0x212b: []int32{229}, + 0x2132: []int32{8526}, + 0x2160: []int32{8560}, + 0x2161: []int32{8561}, + 0x2162: []int32{8562}, + 0x2163: []int32{8563}, + 0x2164: []int32{8564}, + 0x2165: []int32{8565}, + 0x2166: []int32{8566}, + 0x2167: []int32{8567}, + 0x2168: []int32{8568}, + 0x2169: []int32{8569}, + 0x216a: []int32{8570}, + 0x216b: []int32{8571}, + 0x216c: []int32{8572}, + 0x216d: []int32{8573}, + 0x216e: []int32{8574}, + 0x216f: []int32{8575}, + 0x2183: []int32{8580}, + 0x24b6: []int32{9424}, + 0x24b7: []int32{9425}, + 0x24b8: []int32{9426}, + 0x24b9: []int32{9427}, + 0x24ba: []int32{9428}, + 0x24bb: []int32{9429}, + 0x24bc: []int32{9430}, + 0x24bd: []int32{9431}, + 0x24be: []int32{9432}, + 0x24bf: []int32{9433}, + 0x24c0: []int32{9434}, + 0x24c1: []int32{9435}, + 0x24c2: []int32{9436}, + 0x24c3: []int32{9437}, + 0x24c4: []int32{9438}, + 0x24c5: []int32{9439}, + 0x24c6: []int32{9440}, + 0x24c7: []int32{9441}, + 0x24c8: []int32{9442}, + 0x24c9: []int32{9443}, + 0x24ca: []int32{9444}, + 0x24cb: []int32{9445}, + 0x24cc: []int32{9446}, + 0x24cd: []int32{9447}, + 0x24ce: []int32{9448}, + 0x24cf: []int32{9449}, + 0x2c00: []int32{11312}, + 0x2c01: []int32{11313}, + 0x2c02: []int32{11314}, + 0x2c03: []int32{11315}, + 0x2c04: []int32{11316}, + 0x2c05: []int32{11317}, + 0x2c06: []int32{11318}, + 0x2c07: []int32{11319}, + 0x2c08: []int32{11320}, + 0x2c09: []int32{11321}, + 0x2c0a: []int32{11322}, + 0x2c0b: []int32{11323}, + 0x2c0c: []int32{11324}, + 0x2c0d: []int32{11325}, + 0x2c0e: []int32{11326}, + 0x2c0f: []int32{11327}, + 0x2c10: []int32{11328}, + 0x2c11: []int32{11329}, + 0x2c12: []int32{11330}, + 0x2c13: []int32{11331}, + 0x2c14: []int32{11332}, + 0x2c15: []int32{11333}, + 0x2c16: []int32{11334}, + 0x2c17: []int32{11335}, + 0x2c18: []int32{11336}, + 0x2c19: []int32{11337}, + 0x2c1a: []int32{11338}, + 0x2c1b: []int32{11339}, + 0x2c1c: []int32{11340}, + 0x2c1d: []int32{11341}, + 0x2c1e: []int32{11342}, + 0x2c1f: []int32{11343}, + 0x2c20: []int32{11344}, + 0x2c21: []int32{11345}, + 0x2c22: []int32{11346}, + 0x2c23: []int32{11347}, + 0x2c24: []int32{11348}, + 0x2c25: []int32{11349}, + 0x2c26: []int32{11350}, + 0x2c27: []int32{11351}, + 0x2c28: []int32{11352}, + 0x2c29: []int32{11353}, + 0x2c2a: []int32{11354}, + 0x2c2b: []int32{11355}, + 0x2c2c: []int32{11356}, + 0x2c2d: []int32{11357}, + 0x2c2e: []int32{11358}, + 0x2c60: []int32{11361}, + 0x2c62: []int32{619}, + 0x2c63: []int32{7549}, + 0x2c64: []int32{637}, + 0x2c67: []int32{11368}, + 0x2c69: []int32{11370}, + 0x2c6b: []int32{11372}, + 0x2c6d: []int32{593}, + 0x2c6e: []int32{625}, + 0x2c6f: []int32{592}, + 0x2c70: []int32{594}, + 0x2c72: []int32{11379}, + 0x2c75: []int32{11382}, + 0x2c7e: []int32{575}, + 0x2c7f: []int32{576}, + 0x2c80: []int32{11393}, + 0x2c82: []int32{11395}, + 0x2c84: []int32{11397}, + 0x2c86: []int32{11399}, + 0x2c88: []int32{11401}, + 0x2c8a: []int32{11403}, + 0x2c8c: []int32{11405}, + 0x2c8e: []int32{11407}, + 0x2c90: []int32{11409}, + 0x2c92: []int32{11411}, + 0x2c94: []int32{11413}, + 0x2c96: []int32{11415}, + 0x2c98: []int32{11417}, + 0x2c9a: []int32{11419}, + 0x2c9c: []int32{11421}, + 0x2c9e: []int32{11423}, + 0x2ca0: []int32{11425}, + 0x2ca2: []int32{11427}, + 0x2ca4: []int32{11429}, + 0x2ca6: []int32{11431}, + 0x2ca8: []int32{11433}, + 0x2caa: []int32{11435}, + 0x2cac: []int32{11437}, + 0x2cae: []int32{11439}, + 0x2cb0: []int32{11441}, + 0x2cb2: []int32{11443}, + 0x2cb4: []int32{11445}, + 0x2cb6: []int32{11447}, + 0x2cb8: []int32{11449}, + 0x2cba: []int32{11451}, + 0x2cbc: []int32{11453}, + 0x2cbe: []int32{11455}, + 0x2cc0: []int32{11457}, + 0x2cc2: []int32{11459}, + 0x2cc4: []int32{11461}, + 0x2cc6: []int32{11463}, + 0x2cc8: []int32{11465}, + 0x2cca: []int32{11467}, + 0x2ccc: []int32{11469}, + 0x2cce: []int32{11471}, + 0x2cd0: []int32{11473}, + 0x2cd2: []int32{11475}, + 0x2cd4: []int32{11477}, + 0x2cd6: []int32{11479}, + 0x2cd8: []int32{11481}, + 0x2cda: []int32{11483}, + 0x2cdc: []int32{11485}, + 0x2cde: []int32{11487}, + 0x2ce0: []int32{11489}, + 0x2ce2: []int32{11491}, + 0x2ceb: []int32{11500}, + 0x2ced: []int32{11502}, + 0x2cf2: []int32{11507}, + 0xa640: []int32{42561}, + 0xa642: []int32{42563}, + 0xa644: []int32{42565}, + 0xa646: []int32{42567}, + 0xa648: []int32{42569}, + 0xa64a: []int32{42571}, + 0xa64c: []int32{42573}, + 0xa64e: []int32{42575}, + 0xa650: []int32{42577}, + 0xa652: []int32{42579}, + 0xa654: []int32{42581}, + 0xa656: []int32{42583}, + 0xa658: []int32{42585}, + 0xa65a: []int32{42587}, + 0xa65c: []int32{42589}, + 0xa65e: []int32{42591}, + 0xa660: []int32{42593}, + 0xa662: []int32{42595}, + 0xa664: []int32{42597}, + 0xa666: []int32{42599}, + 0xa668: []int32{42601}, + 0xa66a: []int32{42603}, + 0xa66c: []int32{42605}, + 0xa680: []int32{42625}, + 0xa682: []int32{42627}, + 0xa684: []int32{42629}, + 0xa686: []int32{42631}, + 0xa688: []int32{42633}, + 0xa68a: []int32{42635}, + 0xa68c: []int32{42637}, + 0xa68e: []int32{42639}, + 0xa690: []int32{42641}, + 0xa692: []int32{42643}, + 0xa694: []int32{42645}, + 0xa696: []int32{42647}, + 0xa698: []int32{42649}, + 0xa69a: []int32{42651}, + 0xa722: []int32{42787}, + 0xa724: []int32{42789}, + 0xa726: []int32{42791}, + 0xa728: []int32{42793}, + 0xa72a: []int32{42795}, + 0xa72c: []int32{42797}, + 0xa72e: []int32{42799}, + 0xa732: []int32{42803}, + 0xa734: []int32{42805}, + 0xa736: []int32{42807}, + 0xa738: []int32{42809}, + 0xa73a: []int32{42811}, + 0xa73c: []int32{42813}, + 0xa73e: []int32{42815}, + 0xa740: []int32{42817}, + 0xa742: []int32{42819}, + 0xa744: []int32{42821}, + 0xa746: []int32{42823}, + 0xa748: []int32{42825}, + 0xa74a: []int32{42827}, + 0xa74c: []int32{42829}, + 0xa74e: []int32{42831}, + 0xa750: []int32{42833}, + 0xa752: []int32{42835}, + 0xa754: []int32{42837}, + 0xa756: []int32{42839}, + 0xa758: []int32{42841}, + 0xa75a: []int32{42843}, + 0xa75c: []int32{42845}, + 0xa75e: []int32{42847}, + 0xa760: []int32{42849}, + 0xa762: []int32{42851}, + 0xa764: []int32{42853}, + 0xa766: []int32{42855}, + 0xa768: []int32{42857}, + 0xa76a: []int32{42859}, + 0xa76c: []int32{42861}, + 0xa76e: []int32{42863}, + 0xa779: []int32{42874}, + 0xa77b: []int32{42876}, + 0xa77d: []int32{7545}, + 0xa77e: []int32{42879}, + 0xa780: []int32{42881}, + 0xa782: []int32{42883}, + 0xa784: []int32{42885}, + 0xa786: []int32{42887}, + 0xa78b: []int32{42892}, + 0xa78d: []int32{613}, + 0xa790: []int32{42897}, + 0xa792: []int32{42899}, + 0xa796: []int32{42903}, + 0xa798: []int32{42905}, + 0xa79a: []int32{42907}, + 0xa79c: []int32{42909}, + 0xa79e: []int32{42911}, + 0xa7a0: []int32{42913}, + 0xa7a2: []int32{42915}, + 0xa7a4: []int32{42917}, + 0xa7a6: []int32{42919}, + 0xa7a8: []int32{42921}, + 0xa7aa: []int32{614}, + 0xa7ab: []int32{604}, + 0xa7ac: []int32{609}, + 0xa7ad: []int32{620}, + 0xa7ae: []int32{618}, + 0xa7b0: []int32{670}, + 0xa7b1: []int32{647}, + 0xa7b2: []int32{669}, + 0xa7b3: []int32{43859}, + 0xa7b4: []int32{42933}, + 0xa7b6: []int32{42935}, + 0xa7b8: []int32{42937}, + 0xa7ba: []int32{42939}, + 0xa7bc: []int32{42941}, + 0xa7be: []int32{42943}, + 0xa7c2: []int32{42947}, + 0xa7c4: []int32{42900}, + 0xa7c5: []int32{642}, + 0xa7c6: []int32{7566}, + 0xab70: []int32{5024}, + 0xab71: []int32{5025}, + 0xab72: []int32{5026}, + 0xab73: []int32{5027}, + 0xab74: []int32{5028}, + 0xab75: []int32{5029}, + 0xab76: []int32{5030}, + 0xab77: []int32{5031}, + 0xab78: []int32{5032}, + 0xab79: []int32{5033}, + 0xab7a: []int32{5034}, + 0xab7b: []int32{5035}, + 0xab7c: []int32{5036}, + 0xab7d: []int32{5037}, + 0xab7e: []int32{5038}, + 0xab7f: []int32{5039}, + 0xab80: []int32{5040}, + 0xab81: []int32{5041}, + 0xab82: []int32{5042}, + 0xab83: []int32{5043}, + 0xab84: []int32{5044}, + 0xab85: []int32{5045}, + 0xab86: []int32{5046}, + 0xab87: []int32{5047}, + 0xab88: []int32{5048}, + 0xab89: []int32{5049}, + 0xab8a: []int32{5050}, + 0xab8b: []int32{5051}, + 0xab8c: []int32{5052}, + 0xab8d: []int32{5053}, + 0xab8e: []int32{5054}, + 0xab8f: []int32{5055}, + 0xab90: []int32{5056}, + 0xab91: []int32{5057}, + 0xab92: []int32{5058}, + 0xab93: []int32{5059}, + 0xab94: []int32{5060}, + 0xab95: []int32{5061}, + 0xab96: []int32{5062}, + 0xab97: []int32{5063}, + 0xab98: []int32{5064}, + 0xab99: []int32{5065}, + 0xab9a: []int32{5066}, + 0xab9b: []int32{5067}, + 0xab9c: []int32{5068}, + 0xab9d: []int32{5069}, + 0xab9e: []int32{5070}, + 0xab9f: []int32{5071}, + 0xaba0: []int32{5072}, + 0xaba1: []int32{5073}, + 0xaba2: []int32{5074}, + 0xaba3: []int32{5075}, + 0xaba4: []int32{5076}, + 0xaba5: []int32{5077}, + 0xaba6: []int32{5078}, + 0xaba7: []int32{5079}, + 0xaba8: []int32{5080}, + 0xaba9: []int32{5081}, + 0xabaa: []int32{5082}, + 0xabab: []int32{5083}, + 0xabac: []int32{5084}, + 0xabad: []int32{5085}, + 0xabae: []int32{5086}, + 0xabaf: []int32{5087}, + 0xabb0: []int32{5088}, + 0xabb1: []int32{5089}, + 0xabb2: []int32{5090}, + 0xabb3: []int32{5091}, + 0xabb4: []int32{5092}, + 0xabb5: []int32{5093}, + 0xabb6: []int32{5094}, + 0xabb7: []int32{5095}, + 0xabb8: []int32{5096}, + 0xabb9: []int32{5097}, + 0xabba: []int32{5098}, + 0xabbb: []int32{5099}, + 0xabbc: []int32{5100}, + 0xabbd: []int32{5101}, + 0xabbe: []int32{5102}, + 0xabbf: []int32{5103}, + 0xfb00: []int32{102, 102}, + 0xfb01: []int32{102, 105}, + 0xfb02: []int32{102, 108}, + 0xfb03: []int32{102, 102, 105}, + 0xfb04: []int32{102, 102, 108}, + 0xfb05: []int32{115, 116}, + 0xfb06: []int32{115, 116}, + 0xfb13: []int32{1396, 1398}, + 0xfb14: []int32{1396, 1381}, + 0xfb15: []int32{1396, 1387}, + 0xfb16: []int32{1406, 1398}, + 0xfb17: []int32{1396, 1389}, + 0xff21: []int32{65345}, + 0xff22: []int32{65346}, + 0xff23: []int32{65347}, + 0xff24: []int32{65348}, + 0xff25: []int32{65349}, + 0xff26: []int32{65350}, + 0xff27: []int32{65351}, + 0xff28: []int32{65352}, + 0xff29: []int32{65353}, + 0xff2a: []int32{65354}, + 0xff2b: []int32{65355}, + 0xff2c: []int32{65356}, + 0xff2d: []int32{65357}, + 0xff2e: []int32{65358}, + 0xff2f: []int32{65359}, + 0xff30: []int32{65360}, + 0xff31: []int32{65361}, + 0xff32: []int32{65362}, + 0xff33: []int32{65363}, + 0xff34: []int32{65364}, + 0xff35: []int32{65365}, + 0xff36: []int32{65366}, + 0xff37: []int32{65367}, + 0xff38: []int32{65368}, + 0xff39: []int32{65369}, + 0xff3a: []int32{65370}, + 0x10400: []int32{66600}, + 0x10401: []int32{66601}, + 0x10402: []int32{66602}, + 0x10403: []int32{66603}, + 0x10404: []int32{66604}, + 0x10405: []int32{66605}, + 0x10406: []int32{66606}, + 0x10407: []int32{66607}, + 0x10408: []int32{66608}, + 0x10409: []int32{66609}, + 0x1040a: []int32{66610}, + 0x1040b: []int32{66611}, + 0x1040c: []int32{66612}, + 0x1040d: []int32{66613}, + 0x1040e: []int32{66614}, + 0x1040f: []int32{66615}, + 0x10410: []int32{66616}, + 0x10411: []int32{66617}, + 0x10412: []int32{66618}, + 0x10413: []int32{66619}, + 0x10414: []int32{66620}, + 0x10415: []int32{66621}, + 0x10416: []int32{66622}, + 0x10417: []int32{66623}, + 0x10418: []int32{66624}, + 0x10419: []int32{66625}, + 0x1041a: []int32{66626}, + 0x1041b: []int32{66627}, + 0x1041c: []int32{66628}, + 0x1041d: []int32{66629}, + 0x1041e: []int32{66630}, + 0x1041f: []int32{66631}, + 0x10420: []int32{66632}, + 0x10421: []int32{66633}, + 0x10422: []int32{66634}, + 0x10423: []int32{66635}, + 0x10424: []int32{66636}, + 0x10425: []int32{66637}, + 0x10426: []int32{66638}, + 0x10427: []int32{66639}, + 0x104b0: []int32{66776}, + 0x104b1: []int32{66777}, + 0x104b2: []int32{66778}, + 0x104b3: []int32{66779}, + 0x104b4: []int32{66780}, + 0x104b5: []int32{66781}, + 0x104b6: []int32{66782}, + 0x104b7: []int32{66783}, + 0x104b8: []int32{66784}, + 0x104b9: []int32{66785}, + 0x104ba: []int32{66786}, + 0x104bb: []int32{66787}, + 0x104bc: []int32{66788}, + 0x104bd: []int32{66789}, + 0x104be: []int32{66790}, + 0x104bf: []int32{66791}, + 0x104c0: []int32{66792}, + 0x104c1: []int32{66793}, + 0x104c2: []int32{66794}, + 0x104c3: []int32{66795}, + 0x104c4: []int32{66796}, + 0x104c5: []int32{66797}, + 0x104c6: []int32{66798}, + 0x104c7: []int32{66799}, + 0x104c8: []int32{66800}, + 0x104c9: []int32{66801}, + 0x104ca: []int32{66802}, + 0x104cb: []int32{66803}, + 0x104cc: []int32{66804}, + 0x104cd: []int32{66805}, + 0x104ce: []int32{66806}, + 0x104cf: []int32{66807}, + 0x104d0: []int32{66808}, + 0x104d1: []int32{66809}, + 0x104d2: []int32{66810}, + 0x104d3: []int32{66811}, + 0x10c80: []int32{68800}, + 0x10c81: []int32{68801}, + 0x10c82: []int32{68802}, + 0x10c83: []int32{68803}, + 0x10c84: []int32{68804}, + 0x10c85: []int32{68805}, + 0x10c86: []int32{68806}, + 0x10c87: []int32{68807}, + 0x10c88: []int32{68808}, + 0x10c89: []int32{68809}, + 0x10c8a: []int32{68810}, + 0x10c8b: []int32{68811}, + 0x10c8c: []int32{68812}, + 0x10c8d: []int32{68813}, + 0x10c8e: []int32{68814}, + 0x10c8f: []int32{68815}, + 0x10c90: []int32{68816}, + 0x10c91: []int32{68817}, + 0x10c92: []int32{68818}, + 0x10c93: []int32{68819}, + 0x10c94: []int32{68820}, + 0x10c95: []int32{68821}, + 0x10c96: []int32{68822}, + 0x10c97: []int32{68823}, + 0x10c98: []int32{68824}, + 0x10c99: []int32{68825}, + 0x10c9a: []int32{68826}, + 0x10c9b: []int32{68827}, + 0x10c9c: []int32{68828}, + 0x10c9d: []int32{68829}, + 0x10c9e: []int32{68830}, + 0x10c9f: []int32{68831}, + 0x10ca0: []int32{68832}, + 0x10ca1: []int32{68833}, + 0x10ca2: []int32{68834}, + 0x10ca3: []int32{68835}, + 0x10ca4: []int32{68836}, + 0x10ca5: []int32{68837}, + 0x10ca6: []int32{68838}, + 0x10ca7: []int32{68839}, + 0x10ca8: []int32{68840}, + 0x10ca9: []int32{68841}, + 0x10caa: []int32{68842}, + 0x10cab: []int32{68843}, + 0x10cac: []int32{68844}, + 0x10cad: []int32{68845}, + 0x10cae: []int32{68846}, + 0x10caf: []int32{68847}, + 0x10cb0: []int32{68848}, + 0x10cb1: []int32{68849}, + 0x10cb2: []int32{68850}, + 0x118a0: []int32{71872}, + 0x118a1: []int32{71873}, + 0x118a2: []int32{71874}, + 0x118a3: []int32{71875}, + 0x118a4: []int32{71876}, + 0x118a5: []int32{71877}, + 0x118a6: []int32{71878}, + 0x118a7: []int32{71879}, + 0x118a8: []int32{71880}, + 0x118a9: []int32{71881}, + 0x118aa: []int32{71882}, + 0x118ab: []int32{71883}, + 0x118ac: []int32{71884}, + 0x118ad: []int32{71885}, + 0x118ae: []int32{71886}, + 0x118af: []int32{71887}, + 0x118b0: []int32{71888}, + 0x118b1: []int32{71889}, + 0x118b2: []int32{71890}, + 0x118b3: []int32{71891}, + 0x118b4: []int32{71892}, + 0x118b5: []int32{71893}, + 0x118b6: []int32{71894}, + 0x118b7: []int32{71895}, + 0x118b8: []int32{71896}, + 0x118b9: []int32{71897}, + 0x118ba: []int32{71898}, + 0x118bb: []int32{71899}, + 0x118bc: []int32{71900}, + 0x118bd: []int32{71901}, + 0x118be: []int32{71902}, + 0x118bf: []int32{71903}, + 0x16e40: []int32{93792}, + 0x16e41: []int32{93793}, + 0x16e42: []int32{93794}, + 0x16e43: []int32{93795}, + 0x16e44: []int32{93796}, + 0x16e45: []int32{93797}, + 0x16e46: []int32{93798}, + 0x16e47: []int32{93799}, + 0x16e48: []int32{93800}, + 0x16e49: []int32{93801}, + 0x16e4a: []int32{93802}, + 0x16e4b: []int32{93803}, + 0x16e4c: []int32{93804}, + 0x16e4d: []int32{93805}, + 0x16e4e: []int32{93806}, + 0x16e4f: []int32{93807}, + 0x16e50: []int32{93808}, + 0x16e51: []int32{93809}, + 0x16e52: []int32{93810}, + 0x16e53: []int32{93811}, + 0x16e54: []int32{93812}, + 0x16e55: []int32{93813}, + 0x16e56: []int32{93814}, + 0x16e57: []int32{93815}, + 0x16e58: []int32{93816}, + 0x16e59: []int32{93817}, + 0x16e5a: []int32{93818}, + 0x16e5b: []int32{93819}, + 0x16e5c: []int32{93820}, + 0x16e5d: []int32{93821}, + 0x16e5e: []int32{93822}, + 0x16e5f: []int32{93823}, + 0x1e900: []int32{125218}, + 0x1e901: []int32{125219}, + 0x1e902: []int32{125220}, + 0x1e903: []int32{125221}, + 0x1e904: []int32{125222}, + 0x1e905: []int32{125223}, + 0x1e906: []int32{125224}, + 0x1e907: []int32{125225}, + 0x1e908: []int32{125226}, + 0x1e909: []int32{125227}, + 0x1e90a: []int32{125228}, + 0x1e90b: []int32{125229}, + 0x1e90c: []int32{125230}, + 0x1e90d: []int32{125231}, + 0x1e90e: []int32{125232}, + 0x1e90f: []int32{125233}, + 0x1e910: []int32{125234}, + 0x1e911: []int32{125235}, + 0x1e912: []int32{125236}, + 0x1e913: []int32{125237}, + 0x1e914: []int32{125238}, + 0x1e915: []int32{125239}, + 0x1e916: []int32{125240}, + 0x1e917: []int32{125241}, + 0x1e918: []int32{125242}, + 0x1e919: []int32{125243}, + 0x1e91a: []int32{125244}, + 0x1e91b: []int32{125245}, + 0x1e91c: []int32{125246}, + 0x1e91d: []int32{125247}, + 0x1e91e: []int32{125248}, + 0x1e91f: []int32{125249}, + 0x1e920: []int32{125250}, + 0x1e921: []int32{125251}, +} diff --git a/vendor/github.com/yuin/goldmark/util/util.go b/vendor/github.com/yuin/goldmark/util/util.go new file mode 100644 index 0000000000..3ec73f54f3 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/util/util.go @@ -0,0 +1,992 @@ +// Package util provides utility functions for the goldmark. +package util + +import ( + "bytes" + "io" + "net/url" + "regexp" + "sort" + "strconv" + "unicode" + "unicode/utf8" +) + +// A CopyOnWriteBuffer is a byte buffer that copies buffer when +// it need to be changed. +type CopyOnWriteBuffer struct { + buffer []byte + copied bool +} + +// NewCopyOnWriteBuffer returns a new CopyOnWriteBuffer. +func NewCopyOnWriteBuffer(buffer []byte) CopyOnWriteBuffer { + return CopyOnWriteBuffer{ + buffer: buffer, + copied: false, + } +} + +// Write writes given bytes to the buffer. +// Write allocate new buffer and clears it at the first time. +func (b *CopyOnWriteBuffer) Write(value []byte) { + if !b.copied { + b.buffer = make([]byte, 0, len(b.buffer)+20) + b.copied = true + } + b.buffer = append(b.buffer, value...) +} + +// WriteString writes given string to the buffer. +// WriteString allocate new buffer and clears it at the first time. +func (b *CopyOnWriteBuffer) WriteString(value string) { + b.Write(StringToReadOnlyBytes(value)) +} + +// Append appends given bytes to the buffer. +// Append copy buffer at the first time. +func (b *CopyOnWriteBuffer) Append(value []byte) { + if !b.copied { + tmp := make([]byte, len(b.buffer), len(b.buffer)+20) + copy(tmp, b.buffer) + b.buffer = tmp + b.copied = true + } + b.buffer = append(b.buffer, value...) +} + +// AppendString appends given string to the buffer. +// AppendString copy buffer at the first time. +func (b *CopyOnWriteBuffer) AppendString(value string) { + b.Append(StringToReadOnlyBytes(value)) +} + +// WriteByte writes the given byte to the buffer. +// WriteByte allocate new buffer and clears it at the first time. +func (b *CopyOnWriteBuffer) WriteByte(c byte) { + if !b.copied { + b.buffer = make([]byte, 0, len(b.buffer)+20) + b.copied = true + } + b.buffer = append(b.buffer, c) +} + +// AppendByte appends given bytes to the buffer. +// AppendByte copy buffer at the first time. +func (b *CopyOnWriteBuffer) AppendByte(c byte) { + if !b.copied { + tmp := make([]byte, len(b.buffer), len(b.buffer)+20) + copy(tmp, b.buffer) + b.buffer = tmp + b.copied = true + } + b.buffer = append(b.buffer, c) +} + +// Bytes returns bytes of this buffer. +func (b *CopyOnWriteBuffer) Bytes() []byte { + return b.buffer +} + +// IsCopied returns true if buffer has been copied, otherwise false. +func (b *CopyOnWriteBuffer) IsCopied() bool { + return b.copied +} + +// IsEscapedPunctuation returns true if character at a given index i +// is an escaped punctuation, otherwise false. +func IsEscapedPunctuation(source []byte, i int) bool { + return source[i] == '\\' && i < len(source)-1 && IsPunct(source[i+1]) +} + +// ReadWhile read the given source while pred is true. +func ReadWhile(source []byte, index [2]int, pred func(byte) bool) (int, bool) { + j := index[0] + ok := false + for ; j < index[1]; j++ { + c1 := source[j] + if pred(c1) { + ok = true + continue + } + break + } + return j, ok +} + +// IsBlank returns true if the given string is all space characters. +func IsBlank(bs []byte) bool { + for _, b := range bs { + if !IsSpace(b) { + return false + } + } + return true +} + +// VisualizeSpaces visualize invisible space characters. +func VisualizeSpaces(bs []byte) []byte { + bs = bytes.Replace(bs, []byte(" "), []byte("[SPACE]"), -1) + bs = bytes.Replace(bs, []byte("\t"), []byte("[TAB]"), -1) + bs = bytes.Replace(bs, []byte("\n"), []byte("[NEWLINE]\n"), -1) + bs = bytes.Replace(bs, []byte("\r"), []byte("[CR]"), -1) + return bs +} + +// TabWidth calculates actual width of a tab at the given position. +func TabWidth(currentPos int) int { + return 4 - currentPos%4 +} + +// IndentPosition searches an indent position with the given width for the given line. +// If the line contains tab characters, paddings may be not zero. +// currentPos==0 and width==2: +// +// position: 0 1 +// [TAB]aaaa +// width: 1234 5678 +// +// width=2 is in the tab character. In this case, IndentPosition returns +// (pos=1, padding=2) +func IndentPosition(bs []byte, currentPos, width int) (pos, padding int) { + if width == 0 { + return 0, 0 + } + w := 0 + l := len(bs) + i := 0 + hasTab := false + for ; i < l; i++ { + if bs[i] == '\t' { + w += TabWidth(currentPos + w) + hasTab = true + } else if bs[i] == ' ' { + w++ + } else { + break + } + } + if w >= width { + if !hasTab { + return width, 0 + } + return i, w - width + } + return -1, -1 +} + +// IndentPositionPadding searches an indent position with the given width for the given line. +// This function is mostly same as IndentPosition except this function +// takes account into additional paddings. +func IndentPositionPadding(bs []byte, currentPos, paddingv, width int) (pos, padding int) { + if width == 0 { + return 0, paddingv + } + w := 0 + i := 0 + l := len(bs) + for ; i < l; i++ { + if bs[i] == '\t' { + w += TabWidth(currentPos + w) + } else if bs[i] == ' ' { + w++ + } else { + break + } + } + if w >= width { + return i - paddingv, w - width + } + return -1, -1 +} + +// DedentPosition dedents lines by the given width. +func DedentPosition(bs []byte, currentPos, width int) (pos, padding int) { + if width == 0 { + return 0, 0 + } + w := 0 + l := len(bs) + i := 0 + for ; i < l; i++ { + if bs[i] == '\t' { + w += TabWidth(currentPos + w) + } else if bs[i] == ' ' { + w++ + } else { + break + } + } + if w >= width { + return i, w - width + } + return i, 0 +} + +// DedentPositionPadding dedents lines by the given width. +// This function is mostly same as DedentPosition except this function +// takes account into additional paddings. +func DedentPositionPadding(bs []byte, currentPos, paddingv, width int) (pos, padding int) { + if width == 0 { + return 0, paddingv + } + + w := 0 + i := 0 + l := len(bs) + for ; i < l; i++ { + if bs[i] == '\t' { + w += TabWidth(currentPos + w) + } else if bs[i] == ' ' { + w++ + } else { + break + } + } + if w >= width { + return i - paddingv, w - width + } + return i - paddingv, 0 +} + +// IndentWidth calculate an indent width for the given line. +func IndentWidth(bs []byte, currentPos int) (width, pos int) { + l := len(bs) + for i := 0; i < l; i++ { + b := bs[i] + if b == ' ' { + width++ + pos++ + } else if b == '\t' { + width += TabWidth(currentPos + width) + pos++ + } else { + break + } + } + return +} + +// FirstNonSpacePosition returns a position line that is a first nonspace +// character. +func FirstNonSpacePosition(bs []byte) int { + i := 0 + for ; i < len(bs); i++ { + c := bs[i] + if c == ' ' || c == '\t' { + continue + } + if c == '\n' { + return -1 + } + return i + } + return -1 +} + +// FindClosure returns a position that closes the given opener. +// If codeSpan is set true, it ignores characters in code spans. +// If allowNesting is set true, closures correspond to nested opener will be +// ignored. +func FindClosure(bs []byte, opener, closure byte, codeSpan, allowNesting bool) int { + i := 0 + opened := 1 + codeSpanOpener := 0 + for i < len(bs) { + c := bs[i] + if codeSpan && codeSpanOpener != 0 && c == '`' { + codeSpanCloser := 0 + for ; i < len(bs); i++ { + if bs[i] == '`' { + codeSpanCloser++ + } else { + i-- + break + } + } + if codeSpanCloser == codeSpanOpener { + codeSpanOpener = 0 + } + } else if codeSpanOpener == 0 && c == '\\' && i < len(bs)-1 && IsPunct(bs[i+1]) { + i += 2 + continue + } else if codeSpan && codeSpanOpener == 0 && c == '`' { + for ; i < len(bs); i++ { + if bs[i] == '`' { + codeSpanOpener++ + } else { + i-- + break + } + } + } else if (codeSpan && codeSpanOpener == 0) || !codeSpan { + if c == closure { + opened-- + if opened == 0 { + return i + } + } else if c == opener { + if !allowNesting { + return -1 + } + opened++ + } + } + i++ + } + return -1 +} + +// TrimLeft trims characters in the given s from head of the source. +// bytes.TrimLeft offers same functionalities, but bytes.TrimLeft +// allocates new buffer for the result. +func TrimLeft(source, b []byte) []byte { + i := 0 + for ; i < len(source); i++ { + c := source[i] + found := false + for j := 0; j < len(b); j++ { + if c == b[j] { + found = true + break + } + } + if !found { + break + } + } + return source[i:] +} + +// TrimRight trims characters in the given s from tail of the source. +func TrimRight(source, b []byte) []byte { + i := len(source) - 1 + for ; i >= 0; i-- { + c := source[i] + found := false + for j := 0; j < len(b); j++ { + if c == b[j] { + found = true + break + } + } + if !found { + break + } + } + return source[:i+1] +} + +// TrimLeftLength returns a length of leading specified characters. +func TrimLeftLength(source, s []byte) int { + return len(source) - len(TrimLeft(source, s)) +} + +// TrimRightLength returns a length of trailing specified characters. +func TrimRightLength(source, s []byte) int { + return len(source) - len(TrimRight(source, s)) +} + +// TrimLeftSpaceLength returns a length of leading space characters. +func TrimLeftSpaceLength(source []byte) int { + i := 0 + for ; i < len(source); i++ { + if !IsSpace(source[i]) { + break + } + } + return i +} + +// TrimRightSpaceLength returns a length of trailing space characters. +func TrimRightSpaceLength(source []byte) int { + l := len(source) + i := l - 1 + for ; i >= 0; i-- { + if !IsSpace(source[i]) { + break + } + } + if i < 0 { + return l + } + return l - 1 - i +} + +// TrimLeftSpace returns a subslice of the given string by slicing off all leading +// space characters. +func TrimLeftSpace(source []byte) []byte { + return TrimLeft(source, spaces) +} + +// TrimRightSpace returns a subslice of the given string by slicing off all trailing +// space characters. +func TrimRightSpace(source []byte) []byte { + return TrimRight(source, spaces) +} + +// DoFullUnicodeCaseFolding performs full unicode case folding to given bytes. +func DoFullUnicodeCaseFolding(v []byte) []byte { + var rbuf []byte + cob := NewCopyOnWriteBuffer(v) + n := 0 + for i := 0; i < len(v); i++ { + c := v[i] + if c < 0xb5 { + if c >= 0x41 && c <= 0x5a { + // A-Z to a-z + cob.Write(v[n:i]) + cob.WriteByte(c + 32) + n = i + 1 + } + continue + } + + if !utf8.RuneStart(c) { + continue + } + r, length := utf8.DecodeRune(v[i:]) + if r == utf8.RuneError { + continue + } + folded, ok := unicodeCaseFoldings[r] + if !ok { + continue + } + + cob.Write(v[n:i]) + if rbuf == nil { + rbuf = make([]byte, 4) + } + for _, f := range folded { + l := utf8.EncodeRune(rbuf, f) + cob.Write(rbuf[:l]) + } + i += length - 1 + n = i + 1 + } + if cob.IsCopied() { + cob.Write(v[n:]) + } + return cob.Bytes() +} + +// ReplaceSpaces replaces sequence of spaces with the given repl. +func ReplaceSpaces(source []byte, repl byte) []byte { + var ret []byte + start := -1 + for i, c := range source { + iss := IsSpace(c) + if start < 0 && iss { + start = i + continue + } else if start >= 0 && iss { + continue + } else if start >= 0 { + if ret == nil { + ret = make([]byte, 0, len(source)) + ret = append(ret, source[:start]...) + } + ret = append(ret, repl) + start = -1 + } + if ret != nil { + ret = append(ret, c) + } + } + if start >= 0 && ret != nil { + ret = append(ret, repl) + } + if ret == nil { + return source + } + return ret +} + +// ToRune decode given bytes start at pos and returns a rune. +func ToRune(source []byte, pos int) rune { + i := pos + for ; i >= 0; i-- { + if utf8.RuneStart(source[i]) { + break + } + } + r, _ := utf8.DecodeRune(source[i:]) + return r +} + +// ToValidRune returns 0xFFFD if the given rune is invalid, otherwise v. +func ToValidRune(v rune) rune { + if v == 0 || !utf8.ValidRune(v) { + return rune(0xFFFD) + } + return v +} + +// ToLinkReference converts given bytes into a valid link reference string. +// ToLinkReference performs unicode case folding, trims leading and trailing spaces, converts into lower +// case and replace spaces with a single space character. +func ToLinkReference(v []byte) string { + v = TrimLeftSpace(v) + v = TrimRightSpace(v) + v = DoFullUnicodeCaseFolding(v) + return string(ReplaceSpaces(v, ' ')) +} + +var htmlEscapeTable = [256][]byte{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []byte("""), nil, nil, nil, []byte("&"), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []byte("<"), nil, []byte(">"), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil} + +// EscapeHTMLByte returns HTML escaped bytes if the given byte should be escaped, +// otherwise nil. +func EscapeHTMLByte(b byte) []byte { + return htmlEscapeTable[b] +} + +// EscapeHTML escapes characters that should be escaped in HTML text. +func EscapeHTML(v []byte) []byte { + cob := NewCopyOnWriteBuffer(v) + n := 0 + for i := 0; i < len(v); i++ { + c := v[i] + escaped := htmlEscapeTable[c] + if escaped != nil { + cob.Write(v[n:i]) + cob.Write(escaped) + n = i + 1 + } + } + if cob.IsCopied() { + cob.Write(v[n:]) + } + return cob.Bytes() +} + +// UnescapePunctuations unescapes blackslash escaped punctuations. +func UnescapePunctuations(source []byte) []byte { + cob := NewCopyOnWriteBuffer(source) + limit := len(source) + n := 0 + for i := 0; i < limit; { + c := source[i] + if i < limit-1 && c == '\\' && IsPunct(source[i+1]) { + cob.Write(source[n:i]) + cob.WriteByte(source[i+1]) + i += 2 + n = i + continue + } + i++ + } + if cob.IsCopied() { + cob.Write(source[n:]) + } + return cob.Bytes() +} + +// ResolveNumericReferences resolve numeric references like 'Ӓ" . +func ResolveNumericReferences(source []byte) []byte { + cob := NewCopyOnWriteBuffer(source) + buf := make([]byte, 6, 6) + limit := len(source) + ok := false + n := 0 + for i := 0; i < limit; i++ { + if source[i] == '&' { + pos := i + next := i + 1 + if next < limit && source[next] == '#' { + nnext := next + 1 + if nnext < limit { + nc := source[nnext] + // code point like #x22; + if nnext < limit && nc == 'x' || nc == 'X' { + start := nnext + 1 + i, ok = ReadWhile(source, [2]int{start, limit}, IsHexDecimal) + if ok && i < limit && source[i] == ';' { + v, _ := strconv.ParseUint(BytesToReadOnlyString(source[start:i]), 16, 32) + cob.Write(source[n:pos]) + n = i + 1 + runeSize := utf8.EncodeRune(buf, ToValidRune(rune(v))) + cob.Write(buf[:runeSize]) + continue + } + // code point like #1234; + } else if nc >= '0' && nc <= '9' { + start := nnext + i, ok = ReadWhile(source, [2]int{start, limit}, IsNumeric) + if ok && i < limit && i-start < 8 && source[i] == ';' { + v, _ := strconv.ParseUint(BytesToReadOnlyString(source[start:i]), 0, 32) + cob.Write(source[n:pos]) + n = i + 1 + runeSize := utf8.EncodeRune(buf, ToValidRune(rune(v))) + cob.Write(buf[:runeSize]) + continue + } + } + } + } + i = next - 1 + } + } + if cob.IsCopied() { + cob.Write(source[n:]) + } + return cob.Bytes() +} + +// ResolveEntityNames resolve entity references like 'ö" . +func ResolveEntityNames(source []byte) []byte { + cob := NewCopyOnWriteBuffer(source) + limit := len(source) + ok := false + n := 0 + for i := 0; i < limit; i++ { + if source[i] == '&' { + pos := i + next := i + 1 + if !(next < limit && source[next] == '#') { + start := next + i, ok = ReadWhile(source, [2]int{start, limit}, IsAlphaNumeric) + if ok && i < limit && source[i] == ';' { + name := BytesToReadOnlyString(source[start:i]) + entity, ok := LookUpHTML5EntityByName(name) + if ok { + cob.Write(source[n:pos]) + n = i + 1 + cob.Write(entity.Characters) + continue + } + } + } + i = next - 1 + } + } + if cob.IsCopied() { + cob.Write(source[n:]) + } + return cob.Bytes() +} + +var htmlSpace = []byte("%20") + +// URLEscape escape the given URL. +// If resolveReference is set true: +// 1. unescape punctuations +// 2. resolve numeric references +// 3. resolve entity references +// +// URL encoded values (%xx) are kept as is. +func URLEscape(v []byte, resolveReference bool) []byte { + if resolveReference { + v = UnescapePunctuations(v) + v = ResolveNumericReferences(v) + v = ResolveEntityNames(v) + } + cob := NewCopyOnWriteBuffer(v) + limit := len(v) + n := 0 + + for i := 0; i < limit; { + c := v[i] + if urlEscapeTable[c] == 1 { + i++ + continue + } + if c == '%' && i+2 < limit && IsHexDecimal(v[i+1]) && IsHexDecimal(v[i+1]) { + i += 3 + continue + } + u8len := utf8lenTable[c] + if u8len == 99 { // invalid utf8 leading byte, skip it + i++ + continue + } + if c == ' ' { + cob.Write(v[n:i]) + cob.Write(htmlSpace) + i++ + n = i + continue + } + if int(u8len) >= len(v) { + u8len = int8(len(v) - 1) + } + if u8len == 0 { + i++ + n = i + continue + } + cob.Write(v[n:i]) + stop := i + int(u8len) + if stop > len(v) { + i++ + n = i + continue + } + cob.Write(StringToReadOnlyBytes(url.QueryEscape(string(v[i:stop])))) + i += int(u8len) + n = i + } + if cob.IsCopied() && n < limit { + cob.Write(v[n:]) + } + return cob.Bytes() +} + +// FindURLIndex returns a stop index value if the given bytes seem an URL. +// This function is equivalent to [A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]* . +func FindURLIndex(b []byte) int { + i := 0 + if !(len(b) > 0 && urlTable[b[i]]&7 == 7) { + return -1 + } + i++ + for ; i < len(b); i++ { + c := b[i] + if urlTable[c]&4 != 4 { + break + } + } + if i == 1 || i > 33 || i >= len(b) { + return -1 + } + if b[i] != ':' { + return -1 + } + i++ + for ; i < len(b); i++ { + c := b[i] + if urlTable[c]&1 != 1 { + break + } + } + return i +} + +var emailDomainRegexp = regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*`) + +// FindEmailIndex returns a stop index value if the given bytes seem an email address. +func FindEmailIndex(b []byte) int { + // TODO: eliminate regexps + i := 0 + for ; i < len(b); i++ { + c := b[i] + if emailTable[c]&1 != 1 { + break + } + } + if i == 0 { + return -1 + } + if i >= len(b) || b[i] != '@' { + return -1 + } + i++ + if i >= len(b) { + return -1 + } + match := emailDomainRegexp.FindSubmatchIndex(b[i:]) + if match == nil { + return -1 + } + return i + match[1] +} + +var spaces = []byte(" \t\n\x0b\x0c\x0d") + +var spaceTable = [256]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +var punctTable = [256]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +// a-zA-Z0-9, ;/?:@&=+$,-_.!~*'()# +var urlEscapeTable = [256]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +var utf8lenTable = [256]int8{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 99, 99, 99, 99, 99, 99, 99, 99} + +var urlTable = [256]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 0, 1, 0, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + +var emailTable = [256]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +// UTF8Len returns a byte length of the utf-8 character. +func UTF8Len(b byte) int8 { + return utf8lenTable[b] +} + +// IsPunct returns true if the given character is a punctuation, otherwise false. +func IsPunct(c byte) bool { + return punctTable[c] == 1 +} + +// IsPunctRune returns true if the given rune is a punctuation, otherwise false. +func IsPunctRune(r rune) bool { + return int32(r) <= 256 && IsPunct(byte(r)) || unicode.IsPunct(r) +} + +// IsSpace returns true if the given character is a space, otherwise false. +func IsSpace(c byte) bool { + return spaceTable[c] == 1 +} + +// IsSpaceRune returns true if the given rune is a space, otherwise false. +func IsSpaceRune(r rune) bool { + return int32(r) <= 256 && IsSpace(byte(r)) || unicode.IsSpace(r) +} + +// IsNumeric returns true if the given character is a numeric, otherwise false. +func IsNumeric(c byte) bool { + return c >= '0' && c <= '9' +} + +// IsHexDecimal returns true if the given character is a hexdecimal, otherwise false. +func IsHexDecimal(c byte) bool { + return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F' +} + +// IsAlphaNumeric returns true if the given character is a alphabet or a numeric, otherwise false. +func IsAlphaNumeric(c byte) bool { + return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' +} + +// A BufWriter is a subset of the bufio.Writer . +type BufWriter interface { + io.Writer + Available() int + Buffered() int + Flush() error + WriteByte(c byte) error + WriteRune(r rune) (size int, err error) + WriteString(s string) (int, error) +} + +// A PrioritizedValue struct holds pair of an arbitrary value and a priority. +type PrioritizedValue struct { + // Value is an arbitrary value that you want to prioritize. + Value interface{} + // Priority is a priority of the value. + Priority int +} + +// PrioritizedSlice is a slice of the PrioritizedValues +type PrioritizedSlice []PrioritizedValue + +// Sort sorts the PrioritizedSlice in ascending order. +func (s PrioritizedSlice) Sort() { + sort.Slice(s, func(i, j int) bool { + return s[i].Priority < s[j].Priority + }) +} + +// Remove removes the given value from this slice. +func (s PrioritizedSlice) Remove(v interface{}) PrioritizedSlice { + i := 0 + found := false + for ; i < len(s); i++ { + if s[i].Value == v { + found = true + break + } + } + if !found { + return s + } + return append(s[:i], s[i+1:]...) +} + +// Prioritized returns a new PrioritizedValue. +func Prioritized(v interface{}, priority int) PrioritizedValue { + return PrioritizedValue{v, priority} +} + +func bytesHash(b []byte) uint64 { + var hash uint64 = 5381 + for _, c := range b { + hash = ((hash << 5) + hash) + uint64(c) + } + return hash +} + +// BytesFilter is a efficient data structure for checking whether bytes exist or not. +// BytesFilter is thread-safe. +type BytesFilter interface { + // Add adds given bytes to this set. + Add([]byte) + + // Contains return true if this set contains given bytes, otherwise false. + Contains([]byte) bool + + // Extend copies this filter and adds given bytes to new filter. + Extend(...[]byte) BytesFilter +} + +type bytesFilter struct { + chars [256]uint8 + threshold int + slots [][][]byte +} + +// NewBytesFilter returns a new BytesFilter. +func NewBytesFilter(elements ...[]byte) BytesFilter { + s := &bytesFilter{ + threshold: 3, + slots: make([][][]byte, 64), + } + for _, element := range elements { + s.Add(element) + } + return s +} + +func (s *bytesFilter) Add(b []byte) { + l := len(b) + m := s.threshold + if l < s.threshold { + m = l + } + for i := 0; i < m; i++ { + s.chars[b[i]] |= 1 << uint8(i) + } + h := bytesHash(b) % uint64(len(s.slots)) + slot := s.slots[h] + if slot == nil { + slot = [][]byte{} + } + s.slots[h] = append(slot, b) +} + +func (s *bytesFilter) Extend(bs ...[]byte) BytesFilter { + newFilter := NewBytesFilter().(*bytesFilter) + newFilter.chars = s.chars + newFilter.threshold = s.threshold + for k, v := range s.slots { + newSlot := make([][]byte, len(v)) + copy(newSlot, v) + newFilter.slots[k] = v + } + for _, b := range bs { + newFilter.Add(b) + } + return newFilter +} + +func (s *bytesFilter) Contains(b []byte) bool { + l := len(b) + m := s.threshold + if l < s.threshold { + m = l + } + for i := 0; i < m; i++ { + if (s.chars[b[i]] & (1 << uint8(i))) == 0 { + return false + } + } + h := bytesHash(b) % uint64(len(s.slots)) + slot := s.slots[h] + if slot == nil || len(slot) == 0 { + return false + } + for _, element := range slot { + if bytes.Equal(element, b) { + return true + } + } + return false +} diff --git a/vendor/github.com/yuin/goldmark/util/util_safe.go b/vendor/github.com/yuin/goldmark/util/util_safe.go new file mode 100644 index 0000000000..507a9d0293 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/util/util_safe.go @@ -0,0 +1,13 @@ +// +build appengine js + +package util + +// BytesToReadOnlyString returns a string converted from given bytes. +func BytesToReadOnlyString(b []byte) string { + return string(b) +} + +// StringToReadOnlyBytes returns bytes converted from given string. +func StringToReadOnlyBytes(s string) []byte { + return []byte(s) +} diff --git a/vendor/github.com/yuin/goldmark/util/util_unsafe.go b/vendor/github.com/yuin/goldmark/util/util_unsafe.go new file mode 100644 index 0000000000..d098811044 --- /dev/null +++ b/vendor/github.com/yuin/goldmark/util/util_unsafe.go @@ -0,0 +1,23 @@ +// +build !appengine,!js + +package util + +import ( + "reflect" + "unsafe" +) + +// BytesToReadOnlyString returns a string converted from given bytes. +func BytesToReadOnlyString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// StringToReadOnlyBytes returns bytes converted from given string. +func StringToReadOnlyBytes(s string) (bs []byte) { + sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) + bh := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) + bh.Data = sh.Data + bh.Cap = sh.Len + bh.Len = sh.Len + return +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 924e566864..f4b2774476 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -505,7 +505,6 @@ github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp # github.com/prometheus/client_model v0.2.0 -## explicit github.com/prometheus/client_model/go # github.com/prometheus/common v0.25.0 ## explicit @@ -695,6 +694,17 @@ github.com/xi2/xz # github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c ## explicit github.com/xtgo/uuid +# github.com/yuin/goldmark v1.3.8 +## explicit +github.com/yuin/goldmark +github.com/yuin/goldmark/ast +github.com/yuin/goldmark/extension +github.com/yuin/goldmark/extension/ast +github.com/yuin/goldmark/parser +github.com/yuin/goldmark/renderer +github.com/yuin/goldmark/renderer/html +github.com/yuin/goldmark/text +github.com/yuin/goldmark/util # go.etcd.io/bbolt v1.3.6 ## explicit go.etcd.io/bbolt