From 97f19da347b27a4d12f54784fa8bcbf304aa4fea Mon Sep 17 00:00:00 2001 From: bptato Date: Sat, 13 Mar 2021 13:40:23 +0100 Subject: Moved stuff etc --- Makefile | 8 +- as | 5 - buffer.nim | 462 ----------- config | 399 ---------- config.nim | 139 ---- default.css | 0 display.nim | 406 ---------- dom.nim | 346 --------- entity.json | 2233 ----------------------------------------------------- enums.nim | 93 --- main.nim | 65 -- parser.nim | 498 ------------ radixtree.nim | 153 ---- readme.md | 9 +- src/a.nim | 1 + src/buffer.nim | 458 +++++++++++ src/config | 399 ++++++++++ src/config.nim | 139 ++++ src/default.css | 20 + src/display.nim | 395 ++++++++++ src/dom.nim | 331 ++++++++ src/entity | Bin 0 -> 85288 bytes src/entity.json | 2233 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/entity.nim | 18 + src/enums.nim | 103 +++ src/main.nim | 65 ++ src/parser.nim | 555 +++++++++++++ src/radixtree.nim | 151 ++++ src/style.nim | 42 + src/termattrs.nim | 11 + src/twtio.nim | 180 +++++ src/twtstr.nim | 423 ++++++++++ style.nim | 0 termattrs.nim | 11 - twtio.nim | 180 ----- twtstr.nim | 352 --------- 36 files changed, 5533 insertions(+), 5350 deletions(-) delete mode 100644 as delete mode 100644 buffer.nim delete mode 100644 config delete mode 100644 config.nim delete mode 100644 default.css delete mode 100644 display.nim delete mode 100644 dom.nim delete mode 100644 entity.json delete mode 100644 enums.nim delete mode 100644 main.nim delete mode 100644 parser.nim delete mode 100644 radixtree.nim create mode 100644 src/a.nim create mode 100644 src/buffer.nim create mode 100644 src/config create mode 100644 src/config.nim create mode 100644 src/default.css create mode 100644 src/display.nim create mode 100644 src/dom.nim create mode 100755 src/entity create mode 100644 src/entity.json create mode 100644 src/entity.nim create mode 100644 src/enums.nim create mode 100644 src/main.nim create mode 100644 src/parser.nim create mode 100644 src/radixtree.nim create mode 100644 src/style.nim create mode 100644 src/termattrs.nim create mode 100644 src/twtio.nim create mode 100644 src/twtstr.nim delete mode 100644 style.nim delete mode 100644 termattrs.nim delete mode 100644 twtio.nim delete mode 100644 twtstr.nim diff --git a/Makefile b/Makefile index 74872b8a..569cb2b5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ debug: - nim compile -d:ssl -o:twt main.nim + nim compile -d:ssl -o:twt src/main.nim release: - nim compile -d:release -d:ssl -o:twt main.nim + nim compile -d:release -d:ssl -o:twt src/main.nim release_opt: - nim compile -d:danger -d:ssl -o:twt main.nim + nim compile -d:danger -d:ssl -o:twt src/main.nim clean: - rm ./twt ./dtwt ./twt_opt + rm ./twt all: debug release release_opt diff --git a/as b/as deleted file mode 100644 index 1b43b788..00000000 --- a/as +++ /dev/null @@ -1,5 +0,0 @@ - - -Hello? - - diff --git a/buffer.nim b/buffer.nim deleted file mode 100644 index cb67c417..00000000 --- a/buffer.nim +++ /dev/null @@ -1,462 +0,0 @@ -#beware, awful code ahead - -import options -import uri -import tables -import strutils -import unicode - -import termattrs -import dom -import twtio -import enums -import twtstr - -type - Buffer* = ref BufferObj - BufferObj = object - fmttext*: seq[string] - rawtext*: seq[string] - title*: string - hovertext*: string - width*: int - height*: int - cursorx*: int - cursory*: int - xend*: int - fromx*: int - fromy*: int - nodes*: seq[Node] - links*: seq[Node] - clickables*: seq[Node] - elements*: seq[HtmlElement] - idelements*: Table[string, HtmlElement] - selectedlink*: Node - printwrite*: bool - attrs*: TermAttributes - document*: Document - -proc newBuffer*(attrs: TermAttributes): Buffer = - return Buffer(width: attrs.termWidth, - height: attrs.termHeight, - attrs: attrs) - -func lastLine*(buffer: Buffer): int = - assert(buffer.fmttext.len == buffer.rawtext.len) - return buffer.fmttext.len - 1 - -func lastVisibleLine*(buffer: Buffer): int = - return min(buffer.fromy + buffer.height - 1, buffer.lastLine()) - -func currentLineLength*(buffer: Buffer): int = - return buffer.rawtext[buffer.cursory].width() - -func atPercentOf*(buffer: Buffer): int = - if buffer.fmttext.len == 0: return 100 - return (100 * (buffer.cursory + 1)) div (buffer.lastLine() + 1) - -func fmtBetween*(buffer: Buffer, sx: int, sy: int, ex: int, ey: int): string = - if sy < ey: - result &= buffer.rawtext[sy].runeSubstr(sx) - var i = sy + 1 - while i < ey - 1: - result &= buffer.rawtext[i] - inc i - result &= buffer.rawtext[i].runeSubstr(0, ex - sx) - else: - result &= buffer.rawtext[sy].runeSubstr(sx, ex - sx) - -func visibleText*(buffer: Buffer): string = - return buffer.fmttext[buffer.fromy..buffer.lastVisibleLine()].join("\n") - -func lastNode*(buffer: Buffer): Node = - return buffer.nodes[^1] - -func cursorOnNode*(buffer: Buffer, node: Node): bool = - if node.y == node.ey and node.y == buffer.cursory: - return buffer.cursorx >= node.x and buffer.cursorx < node.ex - else: - return (buffer.cursory == node.y and buffer.cursorx >= node.x) or - (buffer.cursory > node.y and buffer.cursory < node.ey) or - (buffer.cursory == node.ey and buffer.cursorx < node.ex) - -func findSelectedElement*(buffer: Buffer): Option[HtmlElement] = - if buffer.selectedlink != nil and buffer.selectedLink.parentNode of HtmlElement: - return some(HtmlElement(buffer.selectedlink.parentNode)) - for node in buffer.nodes: - if node.isElemNode(): - if node.getFmtLen() > 0: - if buffer.cursorOnNode(node): return some(HtmlElement(node)) - return none(HtmlElement) - -func canScroll*(buffer: Buffer): bool = - return buffer.lastLine() > buffer.height - -func getElementById*(buffer: Buffer, id: string): HtmlElement = - if buffer.idelements.hasKey(id): - return buffer.idelements[id] - return nil - -proc findSelectedNode*(buffer: Buffer): Option[Node] = - for node in buffer.nodes: - if node.getFmtLen() > 0 and node.displayed(): - if buffer.cursory >= node.y and buffer.cursory <= node.y + node.height and buffer.cursorx >= node.x and buffer.cursorx <= node.x + node.width: - return some(node) - return none(Node) - -proc addNode*(buffer: Buffer, htmlNode: Node) = - buffer.nodes.add(htmlNode) - - #TODO - if htmlNode.isTextNode() and htmlNode.parentElement != nil and HtmlElement(htmlNode.parentElement).islink: - buffer.links.add(htmlNode) - - if htmlNode.isElemNode(): - case HtmlElement(htmlNode).tagType - of TAG_INPUT, TAG_OPTION: - if not HtmlElement(htmlNode).hidden: - buffer.clickables.add(htmlNode) - else: discard - elif htmlNode.isTextNode(): - #TODO - if htmlNode.parentElement != nil and HtmlElement(htmlNode.parentElement).islink: - let anchor = htmlNode.ancestor(TAG_A) - assert(anchor != nil) - buffer.clickables.add(anchor) - - if htmlNode.isElemNode(): - let elem = HtmlElement(htmlNode) - buffer.elements.add(elem) - if elem.id != "" and not buffer.idelements.hasKey(elem.id): - buffer.idelements[elem.id] = elem - -proc writefmt*(buffer: Buffer, str: string) = - buffer.fmttext &= str - if buffer.printwrite: - stdout.write(str) - -proc writefmt*(buffer: Buffer, c: char) = - buffer.rawtext &= $c - if buffer.printwrite: - stdout.write(c) - -proc writeraw*(buffer: Buffer, str: string) = - buffer.rawtext &= str - -proc writeraw*(buffer: Buffer, c: char) = - buffer.rawtext &= $c - -proc write*(buffer: Buffer, str: string) = - buffer.writefmt(str) - buffer.writeraw(str) - -proc write*(buffer: Buffer, c: char) = - buffer.writefmt(c) - buffer.writeraw(c) - -proc clearText*(buffer: Buffer) = - buffer.fmttext.setLen(0) - buffer.rawtext.setLen(0) - -proc clearNodes*(buffer: Buffer) = - buffer.nodes.setLen(0) - buffer.links.setLen(0) - buffer.clickables.setLen(0) - buffer.elements.setLen(0) - buffer.idelements.clear() - -proc clearBuffer*(buffer: Buffer) = - buffer.clearText() - buffer.clearNodes() - buffer.cursorx = 0 - buffer.cursory = 0 - buffer.fromx = 0 - buffer.fromy = 0 - buffer.hovertext = "" - buffer.selectedlink = nil - -proc scrollTo*(buffer: Buffer, y: int): bool = - if y == buffer.fromy: - return false - buffer.fromy = min(max(buffer.lastLine() - buffer.height + 1, 0), y) - buffer.cursory = min(max(buffer.fromy, buffer.cursory), buffer.fromy + buffer.height) - return true - -proc cursorTo*(buffer: Buffer, x: int, y: int): bool = - result = false - buffer.cursory = min(max(y, 0), buffer.lastLine()) - if buffer.fromy > buffer.cursory: - buffer.fromy = max(buffer.cursory, 0) - result = true - elif buffer.fromy + buffer.height - 1 <= buffer.cursory: - buffer.fromy = max(buffer.cursory - buffer.height + 2, 0) - result = true - buffer.cursorx = min(max(x, 0), buffer.currentLineLength()) - #buffer.fromX = min(max(buffer.currentLineLength() - buffer.width + 1, 0), 0) #TODO - -proc cursorDown*(buffer: Buffer): bool = - if buffer.cursory < buffer.lastLine(): - inc buffer.cursory - if buffer.cursorx >= buffer.currentLineLength(): - buffer.cursorx = max(buffer.currentLineLength() - 1, 0) - elif buffer.xend > 0: - buffer.cursorx = min(buffer.currentLineLength() - 1, buffer.xend) - if buffer.cursory >= buffer.lastVisibleLine() and buffer.lastVisibleLine() != buffer.lastLine(): - inc buffer.fromy - return true - return false - -proc cursorUp*(buffer: Buffer): bool = - if buffer.cursory > 0: - dec buffer.cursory - if buffer.cursorx > buffer.currentLineLength(): - if buffer.cursorx == 0: - buffer.xend = buffer.cursorx - buffer.cursorx = max(buffer.currentLineLength() - 1, 0) - elif buffer.xend > 0: - buffer.cursorx = min(buffer.currentLineLength() - 1, buffer.xend) - if buffer.cursory < buffer.fromy: - dec buffer.fromy - return true - return false - -proc cursorRight*(buffer: Buffer): bool = - if buffer.cursorx < buffer.currentLineLength() - 1: - inc buffer.cursorx - buffer.xend = 0 - else: - buffer.xend = buffer.cursorx - return false - -proc cursorLeft*(buffer: Buffer): bool = - if buffer.cursorx > 0: - dec buffer.cursorx - buffer.xend = 0 - return false - -proc cursorLineBegin*(buffer: Buffer) = - buffer.cursorx = 0 - buffer.xend = 0 - -proc cursorLineEnd*(buffer: Buffer) = - buffer.cursorx = buffer.currentLineLength() - 1 - buffer.xend = buffer.cursorx - -iterator revnodes*(buffer: Buffer): Node {.inline.} = - var i = buffer.nodes.len - 1 - while i >= 0: - yield buffer.nodes[i] - dec i - -proc cursorNextWord*(buffer: Buffer): bool = - let llen = buffer.currentLineLength() - 1 - var r: Rune - var x = buffer.cursorx - var y = buffer.cursory - if llen >= 0: - fastRuneAt(buffer.rawtext[y], x, r, false) - - while r != Rune(' '): - if x >= llen: - break - inc x - fastRuneAt(buffer.rawtext[y], x, r, false) - - while r == Rune(' '): - if x >= llen: - break - inc x - fastRuneAt(buffer.rawtext[y], x, r, false) - - if x >= llen: - if y < buffer.lastLine(): - inc y - x = 0 - return buffer.cursorTo(x, y) - -proc cursorPrevWord*(buffer: Buffer): bool = - var r: Rune - var x = buffer.cursorx - var y = buffer.cursory - if buffer.currentLineLength() > 0: - fastRuneAt(buffer.rawtext[y], x, r, false) - - while r != Rune(' '): - if x == 0: - break - dec x - fastRuneAt(buffer.rawtext[y], x, r, false) - - while r == Rune(' '): - if x == 0: - break - dec x - fastRuneAt(buffer.rawtext[y], x, r, false) - - if x == 0: - if y > 0: - dec y - x = buffer.rawtext[y].runeLen() - 1 - return buffer.cursorTo(x, y) - -iterator revclickables*(buffer: Buffer): Node {.inline.} = - var i = buffer.clickables.len - 1 - while i >= 0: - yield buffer.clickables[i] - dec i - -proc cursorNextLink*(buffer: Buffer): bool = - for node in buffer.clickables: - if node.y > buffer.cursory or (node.y == buffer.cursorY and node.x > buffer.cursorx): - result = buffer.cursorTo(node.x, node.y) - if buffer.cursorx < buffer.currentLineLength(): - var r: Rune - fastRuneAt(buffer.rawtext[buffer.cursory], buffer.cursorx, r, false) - if r == Rune(' '): - return result or buffer.cursorNextWord() - return result - return false - -proc cursorPrevLink*(buffer: Buffer): bool = - for node in buffer.revclickables: - if node.y < buffer.cursorY or (node.y == buffer.cursorY and node.x < buffer.cursorx): - return buffer.cursorTo(node.x, node.y) - return false - -proc cursorFirstLine*(buffer: Buffer): bool = - if buffer.fromy > 0: - buffer.fromy = 0 - result = true - else: - result = false - - buffer.cursorY = 0 - buffer.cursorLineBegin() - -proc cursorLastLine*(buffer: Buffer): bool = - if buffer.fromy < buffer.lastLine() - buffer.height: - buffer.fromy = buffer.lastLine() - (buffer.height - 2) - result = true - else: - result = false - buffer.cursory = buffer.lastLine() - buffer.cursorLineBegin() - -proc cursorTop*(buffer: Buffer): bool = - buffer.cursorY = buffer.fromy - return false - -proc cursorMiddle*(buffer: Buffer): bool = - buffer.cursorY = min(buffer.fromy + (buffer.height - 2) div 2, buffer.lastLine()) - return false - -proc cursorBottom*(buffer: Buffer): bool = - buffer.cursorY = min(buffer.fromy + buffer.height - 2, buffer.lastLine()) - return false - -proc centerLine*(buffer: Buffer): bool = - let ny = max(min(buffer.cursory - buffer.height div 2, buffer.lastLine() - buffer.height + 2), 0) - if ny != buffer.fromy: - buffer.fromy = ny - return true - return false - -proc halfPageUp*(buffer: Buffer): bool = - buffer.cursory = max(buffer.cursorY - buffer.height div 2 + 1, 0) - let nfy = max(0, buffer.fromy - buffer.height div 2 + 1) - if nfy != buffer.fromy: - buffer.fromy = nfy - return true - return false - -proc halfPageDown*(buffer: Buffer): bool = - buffer.cursory = min(buffer.cursorY + buffer.height div 2 - 1, buffer.lastLine()) - let nfy = min(max(buffer.lastLine() - buffer.height + 2, 0), buffer.fromy + buffer.height div 2 - 1) - if nfy != buffer.fromy: - buffer.fromy = nfy - return true - return false - -proc pageUp*(buffer: Buffer): bool = - buffer.cursorY = max(buffer.cursorY - buffer.height + 1, 1) - buffer.fromy = max(0, buffer.fromy - buffer.height) - return true - -proc pageDown*(buffer: Buffer): bool = - buffer.cursorY = min(buffer.cursorY + buffer.height div 2 - 1, buffer.lastLine()) - buffer.fromy = min(max(buffer.lastLine() - buffer.height + 1, 0), buffer.fromy + buffer.height div 2) - return true - -proc scrollDown*(buffer: Buffer): bool = - if buffer.fromy + buffer.height - 1 <= buffer.lastLine(): - inc buffer.fromy - if buffer.fromy >= buffer.cursory: - discard buffer.cursorDown() - return true - discard buffer.cursorDown() - return false - -proc scrollUp*(buffer: Buffer): bool = - if buffer.fromy > 0: - dec buffer.fromy - if buffer.fromy + buffer.height - 1 <= buffer.cursorY: - discard buffer.cursorUp() - return true - discard buffer.cursorUp() - return false - -proc checkLinkSelection*(buffer: Buffer): bool = - if buffer.selectedlink != nil: - if buffer.cursorOnNode(buffer.selectedlink): - return false - else: - let anchor = buffer.selectedlink.ancestor(TAG_A) - anchor.selected = false - buffer.selectedlink.fmttext = buffer.selectedlink.getFmtText() - buffer.selectedlink = nil - buffer.hovertext = "" - var stack: seq[Node] - stack.add(anchor) - while stack.len > 0: - let elem = stack.pop() - elem.fmttext = elem.getFmtText() - for child in elem.childNodes: - stack.add(child) - for node in buffer.links: - if buffer.cursorOnNode(node): - buffer.selectedlink = node - let anchor = node.ancestor(TAG_A) - assert(anchor != nil) - anchor.selected = true - buffer.hovertext = HtmlAnchorElement(anchor).href - var stack: seq[Node] - stack.add(anchor) - while stack.len > 0: - let elem = stack.pop() - elem.fmttext = elem.getFmtText() - for child in elem.childNodes: - stack.add(child) - return true - return false - -proc gotoAnchor*(buffer: Buffer): bool = - if buffer.document.location.anchor != "": - let node = buffer.getElementById(buffer.document.location.anchor) - if node != nil: - return buffer.scrollTo(max(node.y - buffer.height div 2, 0)) - return false - -proc setLocation*(buffer: Buffer, uri: Uri) = - buffer.document.location = uri - -proc gotoLocation*(buffer: Buffer, uri: Uri) = - buffer.document.location = buffer.document.location.combine(uri) - -proc refreshTermAttrs*(buffer: Buffer): bool = - let newAttrs = getTermAttributes() - if newAttrs != buffer.attrs: - buffer.attrs = newAttrs - buffer.width = newAttrs.termWidth - buffer.height = newAttrs.termHeight - return true - return false diff --git a/config b/config deleted file mode 100644 index 99397288..00000000 --- a/config +++ /dev/null @@ -1,399 +0,0 @@ -#normal mode keybindings -nmap q QUIT -nmap h CURSOR_LEFT -nmap j CURSOR_DOWN -nmap k CURSOR_UP -nmap l CURSOR_RIGHT -nmap \e[D CURSOR_LEFT -nmap \e[B CURSOR_DOWN -nmap \e[A CURSOR_UP -nmap \e[C CURSOR_RIGHT -nmap ^ CURSOR_LINEBEGIN -nmap $ CURSOR_LINEEND -nmap b CURSOR_PREV_WORD -nmap w CURSOR_NEXT_WORD -nmap [ CURSOR_PREV_LINK -nmap ] CURSOR_NEXT_LINK -nmap H CURSOR_TOP -nmap M CURSOR_MIDDLE -nmap L CURSOR_BOTTOM -nmap C-d HALF_PAGE_DOWN -nmap C-u HALF_PAGE_UP -nmap C-f PAGE_DOWN -nmap C-b PAGE_UP -nmap \e[6~ PAGE_DOWN -nmap \e[5~ PAGE_UP -nmap C-e SCROLL_DOWN -nmap C-y SCROLL_UP -nmap J SCROLL_DOWN -nmap K SCROLL_UP -nmap C-m CLICK -nmap C-j CLICK -nmap C-l CHANGE_LOCATION -nmap U RELOAD -nmap r RESHAPE -nmap R REDRAW -nmap gg CURSOR_FIRST_LINE -nmap G CURSOR_LAST_LINE -nmap \e[H CURSOR_FIRST_LINE -nmap \e[F CURSOR_LAST_LINE -nmap z CENTER_LINE -nmap C-g LINE_INFO - -#line editing keybindings -lemap C-m LINED_SUBMIT -lemap C-j LINED_SUBMIT -lemap C-h LINED_BACKSPACE -lemap C-? LINED_BACKSPACE -lemap C-d LINED_DELETE -lemap C-c LINED_CANCEL -lemap \eb LINED_PREV_WORD -lemap \ef LINED_NEXT_WORD -lemap C-b LINED_BACK -lemap C-f LINED_FORWARD -lemap C-u LINED_CLEAR -lemap C-k LINED_KILL -lemap C-w LINED_KILL_WORD -lemap C-v LINED_ESC -lemap C-g LINED_COMPOSE_TOGGLE - -#compose keybindings - -#european -comp a: ä -comp o: ö -comp u: ü -comp u" ű -comp o" ő - -comp a' á -comp e' é -comp i' í -comp o' ó -comp u' ú - -comp sS ß -comp n~ ñ - -#hiragana -comp a あ -comp i い -comp u う -comp e え -comp o お - -comp la ぁ -comp li ぃ -comp lu ぅ -comp le ぇ -comp lo ぉ - -comp ka か -comp ki き -comp ku く -comp ke け -comp ko こ - -comp kka っか -comp kki っき -comp kku っく -comp kke っけ -comp kko っこ - -comp sa さ -comp shi し -comp su す -comp se せ -comp so そ - -comp ssa っさ -comp sshi っし -comp ssu っす -comp sse っせ -comp sso っそ - -comp ta た -comp chi ち -comp tsu つ -comp te て -comp to と - -comp tta った -comp tchi っち -comp ttsu っつ -comp tte って -comp tto っと - -comp na な -comp ni に -comp nu ぬ -comp ne ね -comp no の - -comp ha は -comp hi ひ -comp fu ふ -comp he へ -comp ho ほ - -comp ma ま -comp mi み -comp mu む -comp me め -comp mo も - -comp ya や -comp yu ゆ -comp yo よ - -comp ra ら -comp ri り -comp ru る -comp re れ -comp ro ろ - -comp wa わ -comp wi ゐ -comp we ゑ -comp wo を - -comp ga が -comp gi ぎ -comp gu ぐ -comp ge げ -comp go ご - -comp za ざ -comp ji じ -comp zu ず -comp ze ぜ -comp zo ぞ - -comp da だ -comp dji ぢ -comp dzu づ -comp de で -comp do ど - -comp ba ば -comp bi び -comp bu ぶ -comp be べ -comp bo ぼ - -comp pa ぱ -comp pi ぴ -comp pu ぷ -comp pe ぺ -comp po ぽ - -comp n ん - -comp kya きゃ -comp kyu きゅ -comp kyo きょ - -comp sha しゃ -comp shu しゅ -comp sho しょ - -comp cha ちゃ -comp chu ちゅ -comp cho ちょ - -comp nya にゃ -comp nyu にゅ -comp nyo にょ - -comp hya ひゃ -comp hyu ひゅ -comp hyo ひょ - -comp mya みゃ -comp myu みゅ -comp myo みょ - -comp rya りゃ -comp ryu りゅ -comp ryo りょ - -comp gya ぎゃ -comp gyu ぎゅ -comp gyo ぎょ - -comp ja じゃ -comp ju じゅ -comp jo じょ - -comp bya びゃ -comp byu びゅ -comp byo びょ - -comp pya ぴゃ -comp pyu ぴゅ -comp pyo ぴょ - -comp kwa くゎ -comp gwa ぐゎ - -#katakana -comp A ア -comp I イ -comp U ウ -comp E エ -comp O オ - -comp LA ォ -comp LI ィ -comp LU ゥ -comp LE ェ -comp LO ォ - -comp KA か -comp KI き -comp KU く -comp KE け -comp KO こ - -comp KKA ッカ -comp KKI ッキ -comp KKU ック -comp KKE ッケ -comp KKO ッコ - -comp SA サ -comp SHI シ -comp SU ス -comp SE セ -comp SO ソ - -comp SSA ッサ -comp SSHI ッシ -comp SSU ッス -comp SSE ッセ -comp SSO ッソ - -comp TA タ -comp CHI チ -comp TSU ツ -comp TE テ -comp TO ト - -comp TTA ッタ -comp TCHI ッチ -comp TTSU ッツ -comp TTE ッテ -comp TTO ッと - -comp NA ナ -comp NI ニ -comp NU ヌ -comp NE ネ -comp NO ノ - -comp HA ハ -comp HI ヒ -comp FU フ -comp HE ヘ -comp HO ホ - -comp MA マ -comp MI ミ -comp MU ム -comp ME メ -comp MO モ - -comp YA ヤ -comp YU ユ -comp YO ヨ - -comp RA ラ -comp RI リ -comp RU ル -comp RE レ -comp RO ロ - -comp WA ワ -comp WI ヰ -comp WE ヱ -comp WO ヲ - -comp GA ガ -comp GI ギ -comp GU グ -comp GE ゲ -comp GO ゴ - -comp ZA ザ -comp JI ジ -comp ZU ズ -comp ZE ゼ -comp ZO ゾ - -comp DA ダ -comp DJI ヂ -comp DZU ヅ -comp DE デ -comp DO ド - -comp BA バ -comp BI ビ -comp BU ブ -comp BE ベ -comp BO ボ - -comp PA パ -comp PI ピ -comp PU プ -comp PE ペ -comp PO ポ - -comp N ン -comp xc ー - -comp KYA キャ -comp KYU キュ -comp KYO キョ - -comp SHA シャ -comp SHU シュ -comp SHO ショ - -comp CHA チャ -comp CHU チュ -comp CHO チョ - -comp NYA ニャ -comp NYU ニュ -comp NYO ニョ - -comp HYA ヒャ -comp HYU ヒュ -comp HYO ヒョ - -comp MYA ミャ -comp MYU ミュ -comp MYO ミョ - -comp RYA リャ -comp RYU リュ -comp RYO リョ - -comp GYA ギャ -comp GYU ギュ -comp GYO ギョ - -comp JA ジャ -comp JU ジュ -comp JO ジョ - -comp BYA ビャ -comp BYU ビュ -comp BYO ビョ - -comp PYA ピャ -comp PYU ピュ -comp PYO ピョ - -comp KWA クヮ -comp GWA グヮ diff --git a/config.nim b/config.nim deleted file mode 100644 index 6d185a1d..00000000 --- a/config.nim +++ /dev/null @@ -1,139 +0,0 @@ -import tables -import strutils - -import twtstr -import radixtree - -type - TwtAction* = - enum - NO_ACTION, - ACTION_FEED_NEXT, - ACTION_QUIT, - ACTION_CURSOR_UP, ACTION_CURSOR_DOWN, ACTION_CURSOR_LEFT, ACTION_CURSOR_RIGHT, - ACTION_CURSOR_LINEEND, ACTION_CURSOR_LINEBEGIN, - ACTION_CURSOR_NEXT_WORD, ACTION_CURSOR_PREV_WORD, - ACTION_CURSOR_NEXT_NODE, ACTION_CURSOR_PREV_NODE, - ACTION_CURSOR_NEXT_LINK, ACTION_CURSOR_PREV_LINK, - ACTION_PAGE_DOWN, ACTION_PAGE_UP, - ACTION_HALF_PAGE_DOWN, ACTION_HALF_PAGE_UP, - ACTION_SCROLL_DOWN, ACTION_SCROLL_UP, - ACTION_CLICK, - ACTION_CHANGE_LOCATION, - ACTION_RELOAD, ACTION_RESHAPE, ACTION_REDRAW, - ACTION_CURSOR_FIRST_LINE, ACTION_CURSOR_LAST_LINE, - ACTION_CURSOR_TOP, ACTION_CURSOR_MIDDLE, ACTION_CURSOR_BOTTOM, - ACTION_CENTER_LINE, ACTION_LINE_INFO, - ACTION_LINED_SUBMIT, ACTION_LINED_CANCEL, - ACTION_LINED_BACKSPACE, ACTION_LINED_DELETE, - ACTION_LINED_CLEAR, ACTION_LINED_KILL, ACTION_LINED_KILL_WORD, - ACTION_LINED_BACK, ACTION_LINED_FORWARD, - ACTION_LINED_PREV_WORD, ACTION_LINED_NEXT_WORD, - ACTION_LINED_COMPOSE_TOGGLE, ACTION_LINED_COMPOSE_ON, ACTION_LINED_COMPOSE_OFF - ACTION_LINED_ESC - - ActionMap = Table[string, TwtAction] - ComposeMap = RadixTree[string] - -var normalActionRemap*: ActionMap -var linedActionRemap*: ActionMap -var composeRemap*: ComposeMap - -func getRealKey(key: string): string = - var realk: string - var currchar: char - var control = 0 - var skip = false - for c in key: - if c == '\\': - skip = true - elif skip: - if c == 'e': - realk &= '\e' - else: - realk &= c - skip = false - elif c == 'C': - inc control - currchar = c - elif c == '-' and control == 1: - inc control - elif control == 1: - realk &= 'C' & c - control = 0 - elif control == 2: - realk &= getControlChar(c) - control = 0 - else: - realk &= c - if control == 1: - realk &= 'C' - return realk - -func constructActionTable*(origTable: ActionMap): ActionMap = - var newTable: ActionMap - var strs: seq[string] - for k in origTable.keys: - let realk = getRealKey(k) - var teststr = "" - for c in realk: - teststr &= c - strs.add(teststr) - - for k, v in origTable: - let realk = getRealKey(k) - var teststr = "" - for c in realk: - teststr &= c - if strs.contains(teststr): - newTable[teststr] = ACTION_FEED_NEXT - newTable[realk] = v - return newTable - -proc parseConfigLine(line: string, nmap: var ActionMap, lemap: var ActionMap, - compose: var ComposeMap) = - if line.len == 0 or line[0] == '#': - return - let cmd = line.split(' ') - if cmd.len == 3: - if cmd[0] == "nmap": - nmap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) - elif cmd[0] == "lemap": - lemap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) - elif cmd[0] == "comp": - compose[getRealKey(cmd[1])] = cmd[2] - -proc staticReadKeymap(): (ActionMap, ActionMap, ComposeMap) = - let config = staticRead"config" - var nmap: ActionMap - var lemap: ActionMap - var compose = newRadixTree[string]() - for line in config.split('\n'): - parseConfigLine(line, nmap, lemap, compose) - - nmap = constructActionTable(nmap) - lemap = constructActionTable(lemap) - return (nmap, lemap, compose) - -const (normalActionMap, linedActionMap, composeMap) = staticReadKeymap() - -normalActionRemap = normalActionMap -linedActionRemap = linedActionMap -composeRemap = composeMap - -proc readConfig*(filename: string): bool = - var f: File - let status = f.open(filename, fmRead) - var nmap: ActionMap - var lemap: ActionMap - var compose = newRadixTree[string]() - if status: - var line: TaintedString - while f.readLine(line): - parseConfigLine(line, nmap, lemap, compose) - - normalActionRemap = constructActionTable(normalActionMap) - linedActionRemap = constructActionTable(linedActionMap) - return true - else: - return false diff --git a/default.css b/default.css deleted file mode 100644 index e69de29b..00000000 diff --git a/display.nim b/display.nim deleted file mode 100644 index ff5e63f1..00000000 --- a/display.nim +++ /dev/null @@ -1,406 +0,0 @@ -import terminal -import options -import uri -import strutils -import unicode - -import buffer -import termattrs -import dom -import twtstr -import twtio -import config -import enums - -proc clearStatusMsg*(at: int) = - setCursorPos(0, at) - eraseLine() - -proc statusMsg*(str: string, at: int) = - clearStatusMsg(at) - print(str.ansiStyle(styleReverse).ansiReset()) - -type - RenderState = object - x: int - y: int - lastwidth: int - fmtline: string - rawline: string - centerqueue: seq[Node] - centerlen: int - blanklines: int - blankspaces: int - nextspaces: int - docenter: bool - indent: int - listval: int - -func newRenderState(): RenderState = - return RenderState(blanklines: 1) - -proc write(state: var RenderState, s: string) = - state.fmtline &= s - state.rawline &= s - -proc write(state: var RenderState, fs: string, rs: string) = - state.fmtline &= fs - state.rawline &= rs - -proc flushLine(buffer: Buffer, state: var RenderState) = - if state.rawline.len == 0: - inc state.blanklines - assert(state.rawline.runeLen() < buffer.width, "line too long:\n" & state.rawline) - buffer.writefmt(state.fmtline) - buffer.writeraw(state.rawline) - state.x = 0 - inc state.y - state.nextspaces = 0 - state.fmtline = "" - state.rawline = "" - -proc addSpaces(buffer: Buffer, state: var RenderState, n: int) = - if state.x + n > buffer.width: - buffer.flushLine(state) - return - state.blankspaces += n - state.write(' '.repeat(n)) - state.x += n - -proc writeWrappedText(buffer: Buffer, state: var RenderState, node: Node) = - state.lastwidth = 0 - var n = 0 - var fmtword = "" - var rawword = "" - var prevl = false - let fmttext = node.getFmtText() - for w in fmttext: - if w.len > 0 and w[0] == '\e': - fmtword &= w - continue - - for r in w.runes: - if r == Rune(' '): - if rawword.len > 0 and rawword[0] == ' ' and prevl: #first byte can't fool comparison to ascii - fmtword = fmtword.substr(1) - rawword = rawword.substr(1) - state.x -= 1 - prevl = false - state.write(fmtword, rawword) - fmtword = "" - rawword = "" - - if r == Rune('\n'): - state.write(fmtword, rawword) - buffer.flushLine(state) - rawword = "" - fmtword = "" - else: - fmtword &= r - rawword &= r - - state.x += r.width() - - if state.x >= buffer.width: - state.lastwidth = max(state.lastwidth, state.x) - buffer.flushLine(state) - state.x = rawword.width() - prevl = true - else: - state.lastwidth = max(state.lastwidth, state.x) - - inc n - - state.write(fmtword, rawword) - if prevl: - state.x += rawword.width() - prevl = false - - state.lastwidth = max(state.lastwidth, state.x) - -proc preAlignNode(buffer: Buffer, node: Node, state: var RenderState) = - let elem = node.nodeAttr() - if state.rawline.len > 0 and node.firstNode() and state.blanklines == 0: - buffer.flushLine(state) - - if node.firstNode(): - while state.blanklines < max(node.parentElement.margin, node.parentElement.margintop): - buffer.flushLine(state) - if elem.parentNode.nodeType == ELEMENT_NODE: - state.indent += elem.parentElement.indent - - if state.rawline.len > 0 and state.blanklines == 0 and node.displayed(): - buffer.addSpaces(state, state.nextspaces) - state.nextspaces = 0 - if state.blankspaces < max(elem.margin, elem.marginleft): - buffer.addSpaces(state, max(elem.margin, elem.marginleft) - state.blankspaces) - - if elem.centered and state.rawline.len == 0 and node.displayed(): - buffer.addSpaces(state, max(buffer.width div 2 - state.centerlen div 2, 0)) - state.centerlen = 0 - - if node.isElemNode() and elem.display == DISPLAY_LIST_ITEM and state.indent > 0: - if state.blanklines == 0: - buffer.flushLine(state) - var listchar = "" - case elem.parentElement.tagType - of TAG_UL: - listchar = "•" - of TAG_OL: - inc state.listval - listchar = $state.listval & ")" - else: - return - buffer.addSpaces(state, state.indent) - state.write(listchar) - state.x += listchar.runeLen() - buffer.addSpaces(state, 1) - -proc postAlignNode(buffer: Buffer, node: Node, state: var RenderState) = - let elem = node.nodeAttr() - - if node.getRawLen() > 0: - state.blanklines = 0 - state.blankspaces = 0 - - if state.rawline.len > 0 and state.blanklines == 0: - state.nextspaces += max(elem.margin, elem.marginright) - #if node.lastNode() and (node.isTextNode() or elem.childNodes.len == 0): - # buffer.flushLine(state) - - if node.lastNode(): - while state.blanklines < max(node.parentElement.margin, node.parentElement.marginbottom): - buffer.flushLine(state) - if elem.parentElement != nil: - state.indent -= elem.parentElement.indent - - if elem.tagType == TAG_BR and not node.firstNode(): - buffer.flushLine(state) - - if elem.display == DISPLAY_LIST_ITEM and node.lastNode(): - buffer.flushLine(state) - -proc renderNode(buffer: Buffer, node: Node, state: var RenderState) = - if not (node.nodeType in {ELEMENT_NODE, TEXT_NODE}): - return - if node.parentNode.nodeType != ELEMENT_NODE: - return - let elem = node.nodeAttr() - if elem.tagType in {TAG_SCRIPT, TAG_STYLE, TAG_NOSCRIPT}: - return - if elem.tagType == TAG_TITLE: - if node.isTextNode(): - buffer.title = node.getRawText() - return - else: discard - if elem.hidden: return - - if not state.docenter: - if elem.centered: - state.centerqueue.add(node) - if node.lastNode() or elem.tagType == TAG_BR: - state.docenter = true - state.centerlen = 0 - for node in state.centerqueue: - state.centerlen += node.getRawLen() - for node in state.centerqueue: - buffer.renderNode(node, state) - state.centerqueue.setLen(0) - state.docenter = false - return - else: - return - if state.centerqueue.len > 0: - state.docenter = true - state.centerlen = 0 - for node in state.centerqueue: - state.centerlen += node.getRawLen() - for node in state.centerqueue: - buffer.renderNode(node, state) - state.centerqueue.setLen(0) - state.docenter = false - - buffer.preAlignNode(node, state) - - node.x = state.x - node.y = state.y - buffer.writeWrappedText(state, node) - node.ex = state.x - node.ey = state.y - node.width = state.lastwidth - node.x - 1 - node.height = state.y - node.y + 1 - - buffer.postAlignNode(node, state) - -proc setLastHtmlLine(buffer: Buffer, state: var RenderState) = - if state.rawline.len != 0: - buffer.flushLine(state) - -proc renderHtml*(buffer: Buffer) = - var stack: seq[Node] - let first = buffer.document - stack.add(first) - - var state = newRenderState() - while stack.len > 0: - let currElem = stack.pop() - buffer.addNode(currElem) - buffer.renderNode(currElem, state) - var i = currElem.childNodes.len - 1 - while i >= 0: - stack.add(currElem.childNodes[i]) - i -= 1 - - buffer.setLastHtmlLine(state) - -proc drawHtml(buffer: Buffer) = - var state = newRenderState() - for node in buffer.nodes: - buffer.renderNode(node, state) - buffer.setLastHtmlLine(state) - -proc statusMsgForBuffer(buffer: Buffer) = - var msg = $(buffer.cursory + 1) & "/" & $(buffer.lastLine() + 1) & " (" & - $buffer.atPercentOf() & "%) " & - "<" & buffer.title & ">" - if buffer.hovertext.len > 0: - msg &= " " & buffer.hovertext - statusMsg(msg.maxString(buffer.width), buffer.height) - -proc cursorBufferPos(buffer: Buffer) = - var x = buffer.cursorx - var y = buffer.cursory - 1 - buffer.fromY - termGoto(x, y + 1) - -proc displayBuffer(buffer: Buffer) = - eraseScreen() - termGoto(0, 0) - - print(buffer.visibleText().ansiReset()) - -proc inputLoop(attrs: TermAttributes, buffer: Buffer): bool = - var s = "" - var feedNext = false - while true: - stdout.showCursor() - buffer.cursorBufferPos() - if not feedNext: - s = "" - else: - feedNext = false - let c = getch() - s &= c - let action = getNormalAction(s) - var redraw = false - var reshape = false - var nostatus = false - case action - of ACTION_QUIT: - eraseScreen() - return false - of ACTION_CURSOR_LEFT: redraw = buffer.cursorLeft() - of ACTION_CURSOR_DOWN: redraw = buffer.cursorDown() - of ACTION_CURSOR_UP: redraw = buffer.cursorUp() - of ACTION_CURSOR_RIGHT: redraw = buffer.cursorRight() - of ACTION_CURSOR_LINEBEGIN: buffer.cursorLineBegin() - of ACTION_CURSOR_LINEEND: buffer.cursorLineEnd() - of ACTION_CURSOR_NEXT_WORD: redraw = buffer.cursorNextWord() - of ACTION_CURSOR_PREV_WORD: redraw = buffer.cursorPrevWord() - of ACTION_CURSOR_NEXT_LINK: redraw = buffer.cursorNextLink() - of ACTION_CURSOR_PREV_LINK: redraw = buffer.cursorPrevLink() - of ACTION_PAGE_DOWN: redraw = buffer.pageDown() - of ACTION_PAGE_UP: redraw = buffer.pageUp() - of ACTION_HALF_PAGE_DOWN: redraw = buffer.halfPageDown() - of ACTION_HALF_PAGE_UP: redraw = buffer.halfPageUp() - of ACTION_CURSOR_FIRST_LINE: redraw = buffer.cursorFirstLine() - of ACTION_CURSOR_LAST_LINE: redraw = buffer.cursorLastLine() - of ACTION_CURSOR_TOP: redraw = buffer.cursorTop() - of ACTION_CURSOR_MIDDLE: redraw = buffer.cursorMiddle() - of ACTION_CURSOR_BOTTOM: redraw = buffer.cursorBottom() - of ACTION_CENTER_LINE: redraw = buffer.centerLine() - of ACTION_SCROLL_DOWN: redraw = buffer.scrollDown() - of ACTION_SCROLL_UP: redraw = buffer.scrollUp() - of ACTION_CLICK: - let selectedElem = buffer.findSelectedElement() - if selectedElem.isSome: - case selectedElem.get().tagType - of TAG_INPUT: - clearStatusMsg(buffer.height) - let status = readLine("TEXT: ", HtmlInputElement(selectedElem.get()).value, buffer.width) - if status: - reshape = true - redraw = true - else: discard - if selectedElem.get().islink: - let anchor = HtmlAnchorElement(buffer.selectedlink.ancestor(TAG_A)).href - buffer.gotoLocation(parseUri(anchor)) - return true - of ACTION_CHANGE_LOCATION: - var url = $buffer.document.location - - clearStatusMsg(buffer.height) - let status = readLine("URL: ", url, buffer.width) - if status: - buffer.setLocation(parseUri(url)) - return true - of ACTION_LINE_INFO: - statusMsg("line " & $buffer.cursory & "/" & $buffer.lastLine() & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineLength(), buffer.width) - nostatus = true - of ACTION_FEED_NEXT: - feedNext = true - of ACTION_RELOAD: return true - of ACTION_RESHAPE: - reshape = true - redraw = true - of ACTION_REDRAW: redraw = true - else: discard - stdout.hideCursor() - - let prevlink = buffer.selectedlink - let sel = buffer.checkLinkSelection() - if sel: - buffer.clearText() - buffer.drawHtml() - termGoto(0, buffer.selectedlink.y - buffer.fromy) - stdout.eraseLine() - for i in buffer.selectedlink.y..buffer.selectedlink.ey: - if i < buffer.fromy + buffer.height - 1: - let line = buffer.fmttext[i] - print(line) - print('\n') - print("".ansiReset()) - - if prevlink != nil: - buffer.clearText() - buffer.drawHtml() - termGoto(0, prevlink.y - buffer.fromy) - for i in prevlink.y..prevlink.ey: - if i < buffer.fromy + buffer.height - 1: - let line = buffer.fmttext[i] - stdout.eraseLine() - print(line) - print('\n') - print("".ansiReset()) - - if buffer.refreshTermAttrs(): - redraw = true - reshape = true - - if reshape: - buffer.clearText() - buffer.drawHtml() - if redraw: - buffer.displayBuffer() - - if not nostatus: - buffer.statusMsgForBuffer() - else: - nostatus = false - -proc displayPage*(attrs: TermAttributes, buffer: Buffer): bool = - #buffer.printwrite = true - discard buffer.gotoAnchor() - buffer.displayBuffer() - buffer.statusMsgForBuffer() - return inputLoop(attrs, buffer) - diff --git a/dom.nim b/dom.nim deleted file mode 100644 index b018e0f2..00000000 --- a/dom.nim +++ /dev/null @@ -1,346 +0,0 @@ -import terminal -import uri -import unicode -import strutils -import tables - -import twtstr -import twtio -import enums - -type - EventTarget* = ref EventTargetObj - EventTargetObj = object of RootObj - - Node* = ref NodeObj - NodeObj = object of EventTargetObj - nodeType*: NodeType - childNodes*: seq[Node] - firstChild*: Node - isConnected*: bool - lastChild*: Node - nextSibling*: Node - previousSibling*: Node - parentNode*: Node - parentElement*: Element - ownerDocument*: Document - - rawtext*: string - fmttext*: seq[string] - x*: int - y*: int - ex*: int - ey*: int - width*: int - height*: int - hidden*: bool - - Attr* = ref AttrObj - AttrObj = object of NodeObj - namespaceURI*: string - prefix*: string - localName*: string - name*: string - value*: string - ownerElement*: Element - - Document* = ref DocumentObj - DocumentObj = object of NodeObj - location*: Uri - - CharacterData* = ref CharacterDataObj - CharacterDataObj = object of NodeObj - data*: string - length*: int - - Text* = ref TextObj - TextObj = object of CharacterDataObj - wholeText*: string - - Comment* = ref CommentObj - CommentObj = object of CharacterDataObj - - Element* = ref ElementObj - ElementObj = object of NodeObj - namespaceURI*: string - prefix*: string - localName*: string - tagName*: string - tagType*: TagType - - id*: string - classList*: seq[string] - attributes*: Table[string, Attr] - - margintop*: int - marginbottom*: int - marginleft*: int - marginright*: int - margin*: int - centered*: bool - display*: DisplayType - innerText*: string - bold*: bool - italic*: bool - underscore*: bool - islink*: bool - selected*: bool - numChildNodes*: int - indent*: int - - HTMLElement* = ref HTMLElementObj - HTMLElementObj = object of ElementObj - - HTMLInputElement* = ref HTMLInputElementObj - HTMLInputElementObj = object of HTMLElementObj - itype*: InputType - autofocus*: bool - required*: bool - value*: string - size*: int - - HTMLAnchorElement* = ref HTMLAnchorElementObj - HTMLAnchorElementObj = object of HTMLElementObj - href*: string - - HTMLSelectElement* = ref HTMLSelectElementObj - HTMLSelectElementObj = object of HTMLElementObj - name*: string - value*: string - valueSet*: bool - - HTMLOptionElement* = ref HTMLOptionElementObj - HTMLOptionElementObj = object of HTMLElementObj - value*: string - - HTMLHeadingElement* = ref HTMLHeadingElementObj - HTMLHeadingElementObj = object of HTMLElementObj - rank*: uint16 - - HTMLBRElement* = ref HTMLBRElementObj - HTMLBRElementObj = object of HTMLElementObj - - -func getTagTypeMap(): Table[string, TagType] = - for i in low(TagType) .. high(TagType): - let enumname = $TagType(i) - let tagname = enumname.split('_')[1..^1].join("_").tolower() - result[tagname] = TagType(i) - -func getInputTypeMap(): Table[string, InputType] = - for i in low(InputType) .. high(InputType): - let enumname = $InputType(i) - let tagname = enumname.split('_')[1..^1].join("_").tolower() - result[tagname] = InputType(i) - -const tagTypeMap = getTagTypeMap() -const inputTypeMap = getInputTypeMap() - -func tagType*(s: string): TagType = - if tagTypeMap.hasKey(s): - return tagTypeMap[s] - else: - return TAG_UNKNOWN - -func inputType*(s: string): InputType = - if inputTypeMap.hasKey(s): - return inputTypeMap[s] - else: - return INPUT_UNKNOWN - -#TODO -func nodeAttr*(node: Node): HtmlElement = - case node.nodeType - of TEXT_NODE: return HtmlElement(node.parentElement) - of ELEMENT_NODE: return HtmlElement(node) - else: assert(false) - -func displayed*(node: Node): bool = - return node.rawtext.len > 0 and node.nodeAttr().display != DISPLAY_NONE - -func isTextNode*(node: Node): bool = - return node.nodeType == TEXT_NODE - -func isElemNode*(node: Node): bool = - return node.nodeType == ELEMENT_NODE - -func isComment*(node: Node): bool = - return node.nodeType == COMMENT_NODE - -func isCData*(node: Node): bool = - return node.nodeType == CDATA_SECTION_NODE - -func isDocument*(node: Node): bool = - return node.nodeType == DOCUMENT_NODE - -func getFmtLen*(htmlNode: Node): int = - return htmlNode.fmttext.join().runeLen() - -func getRawLen*(htmlNode: Node): int = - return htmlNode.rawtext.runeLen() - -func firstNode*(htmlNode: Node): bool = - return htmlNode.parentElement != nil and htmlNode.parentElement.childNodes[0] == htmlNode - -func lastNode*(htmlNode: Node): bool = - return htmlNode.parentElement != nil and htmlNode.parentElement.childNodes[^1] == htmlNode - -func toInputType*(str: string): InputType = - case str - of "button": INPUT_BUTTON - of "checkbox": INPUT_CHECKBOX - of "color": INPUT_COLOR - of "date": INPUT_DATE - of "datetime_local": INPUT_DATETIME_LOCAL - of "email": INPUT_EMAIL - of "file": INPUT_FILE - of "hidden": INPUT_HIDDEN - of "image": INPUT_IMAGE - of "month": INPUT_MONTH - of "number": INPUT_NUMBER - of "password": INPUT_PASSWORD - of "radio": INPUT_RADIO - of "range": INPUT_RANGE - of "reset": INPUT_RESET - of "search": INPUT_SEARCH - of "submit": INPUT_SUBMIT - of "tel": INPUT_TEL - of "text": INPUT_TEXT - of "time": INPUT_TIME - of "url": INPUT_URL - of "week": INPUT_WEEK - else: INPUT_UNKNOWN - -func toInputSize*(str: string): int = - if str.len == 0: - return 20 - for c in str: - if not c.isDigit: - return 20 - return str.parseInt() - -func getFmtInput(inputElement: HtmlInputElement): seq[string] = - case inputElement.itype - of INPUT_TEXT, INPUT_SEARCH: - let valueFit = fitValueToSize(inputElement.value, inputElement.size) - return valueFit.ansiStyle(styleUnderscore).ansiReset().buttonFmt() - of INPUT_SUBMIT: - return inputElement.value.buttonFmt() - else: discard - -func getRawInput(inputElement: HtmlInputElement): string = - case inputElement.itype - of INPUT_TEXT, INPUT_SEARCH: - return inputElement.value.fitValueToSize(inputElement.size).buttonRaw() - of INPUT_SUBMIT: - return inputElement.value.buttonRaw() - else: discard - -#TODO -func ancestor*(htmlNode: Node, tagType: TagType): HtmlElement = - result = HtmlElement(htmlNode.parentElement) - while result != nil and result.tagType != tagType: - result = HtmlElement(result.parentElement) - -func displayWhitespace*(htmlElem: HtmlElement): bool = - return htmlElem.display == DISPLAY_INLINE or htmlElem.display == DISPLAY_INLINE_BLOCK - -proc getRawText*(htmlNode: Node): string = - if htmlNode.isElemNode(): - case HtmlElement(htmlNode).tagType - of TAG_INPUT: return HtmlInputElement(htmlNode).getRawInput() - else: return "" - elif htmlNode.isTextNode(): - let chardata = CharacterData(htmlNode) - if htmlNode.parentElement != nil and htmlNode.parentElement.tagType != TAG_PRE: - result = chardata.data.remove("\n") - if unicode.strip(result).runeLen() > 0: - if htmlNode.nodeAttr().display != DISPLAY_INLINE: - if htmlNode.previousSibling == nil or htmlNode.previousSibling.nodeAttr().displayWhitespace(): - result = unicode.strip(result, true, false) - if htmlNode.nextSibling == nil or htmlNode.nextSibling.nodeAttr().displayWhitespace(): - result = unicode.strip(result, false, true) - else: - result = "" - else: - result = unicode.strip(chardata.data) - if htmlNode.parentElement != nil and htmlNode.parentElement.tagType == TAG_OPTION: - result = result.buttonRaw() - else: - assert(false) - -func getFmtText*(htmlNode: Node): seq[string] = - if htmlNode.isElemNode(): - case HtmlElement(htmlNode).tagType - of TAG_INPUT: return HtmlInputElement(htmlNode).getFmtInput() - else: return @[] - elif htmlNode.isTextNode(): - let chardata = CharacterData(htmlNode) - result &= chardata.data - if htmlNode.parentElement != nil: - #TODO - if HtmlElement(htmlNode.parentElement).islink: - result = result.ansiFgColor(fgBlue).ansiReset() - let anchor = htmlNode.ancestor(TAG_A) - if anchor != nil and anchor.selected: - result = result.ansiStyle(styleUnderscore).ansiReset() - - if htmlNode.parentElement.tagType == TAG_OPTION: - result = result.ansiFgColor(fgRed).ansiReset() - - #TODO - if HtmlElement(htmlNode.parentElement).bold: - result = result.ansiStyle(styleBright).ansiReset() - if HtmlElement(htmlNode.parentElement).italic: - result = result.ansiStyle(styleItalic).ansiReset() - if HtmlElement(htmlNode.parentElement).underscore: - result = result.ansiStyle(styleUnderscore).ansiReset() - else: - assert(false, "Uhhhh I'm pretty sure we should have parent elements for text nodes?" & htmlNode.rawtext) - else: - assert(false) - -func newDocument*(): Document = - new(result) - result.nodeType = DOCUMENT_NODE - -func newText*(): Text = - new(result) - result.nodeType = TEXT_NODE - -func newComment*(): Comment = - new(result) - result.nodeType = COMMENT_NODE - -func newHtmlElement*(tagType: TagType): HTMLElement = - case tagType - of TAG_INPUT: - result = new(HTMLInputElement) - of TAG_A: - result = new(HTMLAnchorElement) - of TAG_SELECT: - result = new(HTMLSelectElement) - of TAG_OPTION: - result = new(HTMLOptionElement) - of TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6: - result = new(HTMLHeadingElement) - of TAG_BR: - result = new(HTMLBRElement) - else: - new(result) - - result.nodeType = ELEMENT_NODE - result.tagType = tagType - -func newAttr*(parent: Element, key: string, value: string): Attr = - new(result) - result.nodeType = ATTRIBUTE_NODE - result.ownerElement = parent - result.name = key - result.value = value - -func getAttrValue*(element: Element, s: string): string = - let attr = element.attributes.getOrDefault(s, nil) - if attr != nil: - return attr.value - return "" diff --git a/entity.json b/entity.json deleted file mode 100644 index 557170b4..00000000 --- a/entity.json +++ /dev/null @@ -1,2233 +0,0 @@ -{ - "Æ": { "codepoints": [198], "characters": "\u00C6" }, - "Æ": { "codepoints": [198], "characters": "\u00C6" }, - "&": { "codepoints": [38], "characters": "\u0026" }, - "&": { "codepoints": [38], "characters": "\u0026" }, - "Á": { "codepoints": [193], "characters": "\u00C1" }, - "Á": { "codepoints": [193], "characters": "\u00C1" }, - "Ă": { "codepoints": [258], "characters": "\u0102" }, - "Â": { "codepoints": [194], "characters": "\u00C2" }, - "Â": { "codepoints": [194], "characters": "\u00C2" }, - "А": { "codepoints": [1040], "characters": "\u0410" }, - "𝔄": { "codepoints": [120068], "characters": "\uD835\uDD04" }, - "À": { "codepoints": [192], "characters": "\u00C0" }, - "À": { "codepoints": [192], "characters": "\u00C0" }, - "Α": { "codepoints": [913], "characters": "\u0391" }, - "Ā": { "codepoints": [256], "characters": "\u0100" }, - "⩓": { "codepoints": [10835], "characters": "\u2A53" }, - "Ą": { "codepoints": [260], "characters": "\u0104" }, - "𝔸": { "codepoints": [120120], "characters": "\uD835\uDD38" }, - "⁡": { "codepoints": [8289], "characters": "\u2061" }, - "Å": { "codepoints": [197], "characters": "\u00C5" }, - "Å": { "codepoints": [197], "characters": "\u00C5" }, - "𝒜": { "codepoints": [119964], "characters": "\uD835\uDC9C" }, - "≔": { "codepoints": [8788], "characters": "\u2254" }, - "Ã": { "codepoints": [195], "characters": "\u00C3" }, - "Ã": { "codepoints": [195], "characters": "\u00C3" }, - "Ä": { "codepoints": [196], "characters": "\u00C4" }, - "Ä": { "codepoints": [196], "characters": "\u00C4" }, - "∖": { "codepoints": [8726], "characters": "\u2216" }, - "⫧": { "codepoints": [10983], "characters": "\u2AE7" }, - "⌆": { "codepoints": [8966], "characters": "\u2306" }, - "Б": { "codepoints": [1041], "characters": "\u0411" }, - "∵": { "codepoints": [8757], "characters": "\u2235" }, - "ℬ": { "codepoints": [8492], "characters": "\u212C" }, - "Β": { "codepoints": [914], "characters": "\u0392" }, - "𝔅": { "codepoints": [120069], "characters": "\uD835\uDD05" }, - "𝔹": { "codepoints": [120121], "characters": "\uD835\uDD39" }, - "˘": { "codepoints": [728], "characters": "\u02D8" }, - "ℬ": { "codepoints": [8492], "characters": "\u212C" }, - "≎": { "codepoints": [8782], "characters": "\u224E" }, - "Ч": { "codepoints": [1063], "characters": "\u0427" }, - "©": { "codepoints": [169], "characters": "\u00A9" }, - "©": { "codepoints": [169], "characters": "\u00A9" }, - "Ć": { "codepoints": [262], "characters": "\u0106" }, - "⋒": { "codepoints": [8914], "characters": "\u22D2" }, - "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, - "ℭ": { "codepoints": [8493], "characters": "\u212D" }, - "Č": { "codepoints": [268], "characters": "\u010C" }, - "Ç": { "codepoints": [199], "characters": "\u00C7" }, - "Ç": { "codepoints": [199], "characters": "\u00C7" }, - "Ĉ": { "codepoints": [264], "characters": "\u0108" }, - "∰": { "codepoints": [8752], "characters": "\u2230" }, - "Ċ": { "codepoints": [266], "characters": "\u010A" }, - "¸": { "codepoints": [184], "characters": "\u00B8" }, - "·": { "codepoints": [183], "characters": "\u00B7" }, - "ℭ": { "codepoints": [8493], "characters": "\u212D" }, - "Χ": { "codepoints": [935], "characters": "\u03A7" }, - "⊙": { "codepoints": [8857], "characters": "\u2299" }, - "⊖": { "codepoints": [8854], "characters": "\u2296" }, - "⊕": { "codepoints": [8853], "characters": "\u2295" }, - "⊗": { "codepoints": [8855], "characters": "\u2297" }, - "∲": { "codepoints": [8754], "characters": "\u2232" }, - "”": { "codepoints": [8221], "characters": "\u201D" }, - "’": { "codepoints": [8217], "characters": "\u2019" }, - "∷": { "codepoints": [8759], "characters": "\u2237" }, - "⩴": { "codepoints": [10868], "characters": "\u2A74" }, - "≡": { "codepoints": [8801], "characters": "\u2261" }, - "∯": { "codepoints": [8751], "characters": "\u222F" }, - "∮": { "codepoints": [8750], "characters": "\u222E" }, - "ℂ": { "codepoints": [8450], "characters": "\u2102" }, - "∐": { "codepoints": [8720], "characters": "\u2210" }, - "∳": { "codepoints": [8755], "characters": "\u2233" }, - "⨯": { "codepoints": [10799], "characters": "\u2A2F" }, - "𝒞": { "codepoints": [119966], "characters": "\uD835\uDC9E" }, - "⋓": { "codepoints": [8915], "characters": "\u22D3" }, - "≍": { "codepoints": [8781], "characters": "\u224D" }, - "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, - "⤑": { "codepoints": [10513], "characters": "\u2911" }, - "Ђ": { "codepoints": [1026], "characters": "\u0402" }, - "Ѕ": { "codepoints": [1029], "characters": "\u0405" }, - "Џ": { "codepoints": [1039], "characters": "\u040F" }, - "‡": { "codepoints": [8225], "characters": "\u2021" }, - "↡": { "codepoints": [8609], "characters": "\u21A1" }, - "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, - "Ď": { "codepoints": [270], "characters": "\u010E" }, - "Д": { "codepoints": [1044], "characters": "\u0414" }, - "∇": { "codepoints": [8711], "characters": "\u2207" }, - "Δ": { "codepoints": [916], "characters": "\u0394" }, - "𝔇": { "codepoints": [120071], "characters": "\uD835\uDD07" }, - "´": { "codepoints": [180], "characters": "\u00B4" }, - "˙": { "codepoints": [729], "characters": "\u02D9" }, - "˝": { "codepoints": [733], "characters": "\u02DD" }, - "`": { "codepoints": [96], "characters": "\u0060" }, - "˜": { "codepoints": [732], "characters": "\u02DC" }, - "⋄": { "codepoints": [8900], "characters": "\u22C4" }, - "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, - "𝔻": { "codepoints": [120123], "characters": "\uD835\uDD3B" }, - "¨": { "codepoints": [168], "characters": "\u00A8" }, - "⃜": { "codepoints": [8412], "characters": "\u20DC" }, - "≐": { "codepoints": [8784], "characters": "\u2250" }, - "∯": { "codepoints": [8751], "characters": "\u222F" }, - "¨": { "codepoints": [168], "characters": "\u00A8" }, - "⇓": { "codepoints": [8659], "characters": "\u21D3" }, - "⇐": { "codepoints": [8656], "characters": "\u21D0" }, - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, - "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, - "⟸": { "codepoints": [10232], "characters": "\u27F8" }, - "⟺": { "codepoints": [10234], "characters": "\u27FA" }, - "⟹": { "codepoints": [10233], "characters": "\u27F9" }, - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, - "⊨": { "codepoints": [8872], "characters": "\u22A8" }, - "⇑": { "codepoints": [8657], "characters": "\u21D1" }, - "⇕": { "codepoints": [8661], "characters": "\u21D5" }, - "∥": { "codepoints": [8741], "characters": "\u2225" }, - "↓": { "codepoints": [8595], "characters": "\u2193" }, - "⤓": { "codepoints": [10515], "characters": "\u2913" }, - "⇵": { "codepoints": [8693], "characters": "\u21F5" }, - "̑": { "codepoints": [785], "characters": "\u0311" }, - "⥐": { "codepoints": [10576], "characters": "\u2950" }, - "⥞": { "codepoints": [10590], "characters": "\u295E" }, - "↽": { "codepoints": [8637], "characters": "\u21BD" }, - "⥖": { "codepoints": [10582], "characters": "\u2956" }, - "⥟": { "codepoints": [10591], "characters": "\u295F" }, - "⇁": { "codepoints": [8641], "characters": "\u21C1" }, - "⥗": { "codepoints": [10583], "characters": "\u2957" }, - "⊤": { "codepoints": [8868], "characters": "\u22A4" }, - "↧": { "codepoints": [8615], "characters": "\u21A7" }, - "⇓": { "codepoints": [8659], "characters": "\u21D3" }, - "𝒟": { "codepoints": [119967], "characters": "\uD835\uDC9F" }, - "Đ": { "codepoints": [272], "characters": "\u0110" }, - "Ŋ": { "codepoints": [330], "characters": "\u014A" }, - "Ð": { "codepoints": [208], "characters": "\u00D0" }, - "Ð": { "codepoints": [208], "characters": "\u00D0" }, - "É": { "codepoints": [201], "characters": "\u00C9" }, - "É": { "codepoints": [201], "characters": "\u00C9" }, - "Ě": { "codepoints": [282], "characters": "\u011A" }, - "Ê": { "codepoints": [202], "characters": "\u00CA" }, - "Ê": { "codepoints": [202], "characters": "\u00CA" }, - "Э": { "codepoints": [1069], "characters": "\u042D" }, - "Ė": { "codepoints": [278], "characters": "\u0116" }, - "𝔈": { "codepoints": [120072], "characters": "\uD835\uDD08" }, - "È": { "codepoints": [200], "characters": "\u00C8" }, - "È": { "codepoints": [200], "characters": "\u00C8" }, - "∈": { "codepoints": [8712], "characters": "\u2208" }, - "Ē": { "codepoints": [274], "characters": "\u0112" }, - "◻": { "codepoints": [9723], "characters": "\u25FB" }, - "▫": { "codepoints": [9643], "characters": "\u25AB" }, - "Ę": { "codepoints": [280], "characters": "\u0118" }, - "𝔼": { "codepoints": [120124], "characters": "\uD835\uDD3C" }, - "Ε": { "codepoints": [917], "characters": "\u0395" }, - "⩵": { "codepoints": [10869], "characters": "\u2A75" }, - "≂": { "codepoints": [8770], "characters": "\u2242" }, - "⇌": { "codepoints": [8652], "characters": "\u21CC" }, - "ℰ": { "codepoints": [8496], "characters": "\u2130" }, - "⩳": { "codepoints": [10867], "characters": "\u2A73" }, - "Η": { "codepoints": [919], "characters": "\u0397" }, - "Ë": { "codepoints": [203], "characters": "\u00CB" }, - "Ë": { "codepoints": [203], "characters": "\u00CB" }, - "∃": { "codepoints": [8707], "characters": "\u2203" }, - "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, - "Ф": { "codepoints": [1060], "characters": "\u0424" }, - "𝔉": { "codepoints": [120073], "characters": "\uD835\uDD09" }, - "◼": { "codepoints": [9724], "characters": "\u25FC" }, - "▪": { "codepoints": [9642], "characters": "\u25AA" }, - "𝔽": { "codepoints": [120125], "characters": "\uD835\uDD3D" }, - "∀": { "codepoints": [8704], "characters": "\u2200" }, - "ℱ": { "codepoints": [8497], "characters": "\u2131" }, - "ℱ": { "codepoints": [8497], "characters": "\u2131" }, - "Ѓ": { "codepoints": [1027], "characters": "\u0403" }, - ">": { "codepoints": [62], "characters": "\u003E" }, - ">": { "codepoints": [62], "characters": "\u003E" }, - "Γ": { "codepoints": [915], "characters": "\u0393" }, - "Ϝ": { "codepoints": [988], "characters": "\u03DC" }, - "Ğ": { "codepoints": [286], "characters": "\u011E" }, - "Ģ": { "codepoints": [290], "characters": "\u0122" }, - "Ĝ": { "codepoints": [284], "characters": "\u011C" }, - "Г": { "codepoints": [1043], "characters": "\u0413" }, - "Ġ": { "codepoints": [288], "characters": "\u0120" }, - "𝔊": { "codepoints": [120074], "characters": "\uD835\uDD0A" }, - "⋙": { "codepoints": [8921], "characters": "\u22D9" }, - "𝔾": { "codepoints": [120126], "characters": "\uD835\uDD3E" }, - "≥": { "codepoints": [8805], "characters": "\u2265" }, - "⋛": { "codepoints": [8923], "characters": "\u22DB" }, - "≧": { "codepoints": [8807], "characters": "\u2267" }, - "⪢": { "codepoints": [10914], "characters": "\u2AA2" }, - "≷": { "codepoints": [8823], "characters": "\u2277" }, - "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, - "≳": { "codepoints": [8819], "characters": "\u2273" }, - "𝒢": { "codepoints": [119970], "characters": "\uD835\uDCA2" }, - "≫": { "codepoints": [8811], "characters": "\u226B" }, - "Ъ": { "codepoints": [1066], "characters": "\u042A" }, - "ˇ": { "codepoints": [711], "characters": "\u02C7" }, - "^": { "codepoints": [94], "characters": "\u005E" }, - "Ĥ": { "codepoints": [292], "characters": "\u0124" }, - "ℌ": { "codepoints": [8460], "characters": "\u210C" }, - "ℋ": { "codepoints": [8459], "characters": "\u210B" }, - "ℍ": { "codepoints": [8461], "characters": "\u210D" }, - "─": { "codepoints": [9472], "characters": "\u2500" }, - "ℋ": { "codepoints": [8459], "characters": "\u210B" }, - "Ħ": { "codepoints": [294], "characters": "\u0126" }, - "≎": { "codepoints": [8782], "characters": "\u224E" }, - "≏": { "codepoints": [8783], "characters": "\u224F" }, - "Е": { "codepoints": [1045], "characters": "\u0415" }, - "IJ": { "codepoints": [306], "characters": "\u0132" }, - "Ё": { "codepoints": [1025], "characters": "\u0401" }, - "Í": { "codepoints": [205], "characters": "\u00CD" }, - "Í": { "codepoints": [205], "characters": "\u00CD" }, - "Î": { "codepoints": [206], "characters": "\u00CE" }, - "Î": { "codepoints": [206], "characters": "\u00CE" }, - "И": { "codepoints": [1048], "characters": "\u0418" }, - "İ": { "codepoints": [304], "characters": "\u0130" }, - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, - "Ì": { "codepoints": [204], "characters": "\u00CC" }, - "Ì": { "codepoints": [204], "characters": "\u00CC" }, - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, - "Ī": { "codepoints": [298], "characters": "\u012A" }, - "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, - "∬": { "codepoints": [8748], "characters": "\u222C" }, - "∫": { "codepoints": [8747], "characters": "\u222B" }, - "⋂": { "codepoints": [8898], "characters": "\u22C2" }, - "⁣": { "codepoints": [8291], "characters": "\u2063" }, - "⁢": { "codepoints": [8290], "characters": "\u2062" }, - "Į": { "codepoints": [302], "characters": "\u012E" }, - "𝕀": { "codepoints": [120128], "characters": "\uD835\uDD40" }, - "Ι": { "codepoints": [921], "characters": "\u0399" }, - "ℐ": { "codepoints": [8464], "characters": "\u2110" }, - "Ĩ": { "codepoints": [296], "characters": "\u0128" }, - "І": { "codepoints": [1030], "characters": "\u0406" }, - "Ï": { "codepoints": [207], "characters": "\u00CF" }, - "Ï": { "codepoints": [207], "characters": "\u00CF" }, - "Ĵ": { "codepoints": [308], "characters": "\u0134" }, - "Й": { "codepoints": [1049], "characters": "\u0419" }, - "𝔍": { "codepoints": [120077], "characters": "\uD835\uDD0D" }, - "𝕁": { "codepoints": [120129], "characters": "\uD835\uDD41" }, - "𝒥": { "codepoints": [119973], "characters": "\uD835\uDCA5" }, - "Ј": { "codepoints": [1032], "characters": "\u0408" }, - "Є": { "codepoints": [1028], "characters": "\u0404" }, - "Х": { "codepoints": [1061], "characters": "\u0425" }, - "Ќ": { "codepoints": [1036], "characters": "\u040C" }, - "Κ": { "codepoints": [922], "characters": "\u039A" }, - "Ķ": { "codepoints": [310], "characters": "\u0136" }, - "К": { "codepoints": [1050], "characters": "\u041A" }, - "𝔎": { "codepoints": [120078], "characters": "\uD835\uDD0E" }, - "𝕂": { "codepoints": [120130], "characters": "\uD835\uDD42" }, - "𝒦": { "codepoints": [119974], "characters": "\uD835\uDCA6" }, - "Љ": { "codepoints": [1033], "characters": "\u0409" }, - "<": { "codepoints": [60], "characters": "\u003C" }, - "<": { "codepoints": [60], "characters": "\u003C" }, - "Ĺ": { "codepoints": [313], "characters": "\u0139" }, - "Λ": { "codepoints": [923], "characters": "\u039B" }, - "⟪": { "codepoints": [10218], "characters": "\u27EA" }, - "ℒ": { "codepoints": [8466], "characters": "\u2112" }, - "↞": { "codepoints": [8606], "characters": "\u219E" }, - "Ľ": { "codepoints": [317], "characters": "\u013D" }, - "Ļ": { "codepoints": [315], "characters": "\u013B" }, - "Л": { "codepoints": [1051], "characters": "\u041B" }, - "⟨": { "codepoints": [10216], "characters": "\u27E8" }, - "←": { "codepoints": [8592], "characters": "\u2190" }, - "⇤": { "codepoints": [8676], "characters": "\u21E4" }, - "⇆": { "codepoints": [8646], "characters": "\u21C6" }, - "⌈": { "codepoints": [8968], "characters": "\u2308" }, - "⟦": { "codepoints": [10214], "characters": "\u27E6" }, - "⥡": { "codepoints": [10593], "characters": "\u2961" }, - "⇃": { "codepoints": [8643], "characters": "\u21C3" }, - "⥙": { "codepoints": [10585], "characters": "\u2959" }, - "⌊": { "codepoints": [8970], "characters": "\u230A" }, - "↔": { "codepoints": [8596], "characters": "\u2194" }, - "⥎": { "codepoints": [10574], "characters": "\u294E" }, - "⊣": { "codepoints": [8867], "characters": "\u22A3" }, - "↤": { "codepoints": [8612], "characters": "\u21A4" }, - "⥚": { "codepoints": [10586], "characters": "\u295A" }, - "⊲": { "codepoints": [8882], "characters": "\u22B2" }, - "⧏": { "codepoints": [10703], "characters": "\u29CF" }, - "⊴": { "codepoints": [8884], "characters": "\u22B4" }, - "⥑": { "codepoints": [10577], "characters": "\u2951" }, - "⥠": { "codepoints": [10592], "characters": "\u2960" }, - "↿": { "codepoints": [8639], "characters": "\u21BF" }, - "⥘": { "codepoints": [10584], "characters": "\u2958" }, - "↼": { "codepoints": [8636], "characters": "\u21BC" }, - "⥒": { "codepoints": [10578], "characters": "\u2952" }, - "⇐": { "codepoints": [8656], "characters": "\u21D0" }, - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, - "⋚": { "codepoints": [8922], "characters": "\u22DA" }, - "≦": { "codepoints": [8806], "characters": "\u2266" }, - "≶": { "codepoints": [8822], "characters": "\u2276" }, - "⪡": { "codepoints": [10913], "characters": "\u2AA1" }, - "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, - "≲": { "codepoints": [8818], "characters": "\u2272" }, - "𝔏": { "codepoints": [120079], "characters": "\uD835\uDD0F" }, - "⋘": { "codepoints": [8920], "characters": "\u22D8" }, - "⇚": { "codepoints": [8666], "characters": "\u21DA" }, - "Ŀ": { "codepoints": [319], "characters": "\u013F" }, - "⟵": { "codepoints": [10229], "characters": "\u27F5" }, - "⟷": { "codepoints": [10231], "characters": "\u27F7" }, - "⟶": { "codepoints": [10230], "characters": "\u27F6" }, - "⟸": { "codepoints": [10232], "characters": "\u27F8" }, - "⟺": { "codepoints": [10234], "characters": "\u27FA" }, - "⟹": { "codepoints": [10233], "characters": "\u27F9" }, - "𝕃": { "codepoints": [120131], "characters": "\uD835\uDD43" }, - "↙": { "codepoints": [8601], "characters": "\u2199" }, - "↘": { "codepoints": [8600], "characters": "\u2198" }, - "ℒ": { "codepoints": [8466], "characters": "\u2112" }, - "↰": { "codepoints": [8624], "characters": "\u21B0" }, - "Ł": { "codepoints": [321], "characters": "\u0141" }, - "≪": { "codepoints": [8810], "characters": "\u226A" }, - "⤅": { "codepoints": [10501], "characters": "\u2905" }, - "М": { "codepoints": [1052], "characters": "\u041C" }, - " ": { "codepoints": [8287], "characters": "\u205F" }, - "ℳ": { "codepoints": [8499], "characters": "\u2133" }, - "𝔐": { "codepoints": [120080], "characters": "\uD835\uDD10" }, - "∓": { "codepoints": [8723], "characters": "\u2213" }, - "𝕄": { "codepoints": [120132], "characters": "\uD835\uDD44" }, - "ℳ": { "codepoints": [8499], "characters": "\u2133" }, - "Μ": { "codepoints": [924], "characters": "\u039C" }, - "Њ": { "codepoints": [1034], "characters": "\u040A" }, - "Ń": { "codepoints": [323], "characters": "\u0143" }, - "Ň": { "codepoints": [327], "characters": "\u0147" }, - "Ņ": { "codepoints": [325], "characters": "\u0145" }, - "Н": { "codepoints": [1053], "characters": "\u041D" }, - "​": { "codepoints": [8203], "characters": "\u200B" }, - "​": { "codepoints": [8203], "characters": "\u200B" }, - "​": { "codepoints": [8203], "characters": "\u200B" }, - "​": { "codepoints": [8203], "characters": "\u200B" }, - "≫": { "codepoints": [8811], "characters": "\u226B" }, - "≪": { "codepoints": [8810], "characters": "\u226A" }, - " ": { "codepoints": [10], "characters": "\u000A" }, - "𝔑": { "codepoints": [120081], "characters": "\uD835\uDD11" }, - "⁠": { "codepoints": [8288], "characters": "\u2060" }, - " ": { "codepoints": [160], "characters": "\u00A0" }, - "ℕ": { "codepoints": [8469], "characters": "\u2115" }, - "⫬": { "codepoints": [10988], "characters": "\u2AEC" }, - "≢": { "codepoints": [8802], "characters": "\u2262" }, - "≭": { "codepoints": [8813], "characters": "\u226D" }, - "∦": { "codepoints": [8742], "characters": "\u2226" }, - "∉": { "codepoints": [8713], "characters": "\u2209" }, - "≠": { "codepoints": [8800], "characters": "\u2260" }, - "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, - "∄": { "codepoints": [8708], "characters": "\u2204" }, - "≯": { "codepoints": [8815], "characters": "\u226F" }, - "≱": { "codepoints": [8817], "characters": "\u2271" }, - "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, - "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, - "≹": { "codepoints": [8825], "characters": "\u2279" }, - "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, - "≵": { "codepoints": [8821], "characters": "\u2275" }, - "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, - "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, - "⋪": { "codepoints": [8938], "characters": "\u22EA" }, - "⧏̸": { "codepoints": [10703, 824], "characters": "\u29CF\u0338" }, - "⋬": { "codepoints": [8940], "characters": "\u22EC" }, - "≮": { "codepoints": [8814], "characters": "\u226E" }, - "≰": { "codepoints": [8816], "characters": "\u2270" }, - "≸": { "codepoints": [8824], "characters": "\u2278" }, - "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, - "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, - "≴": { "codepoints": [8820], "characters": "\u2274" }, - "⪢̸": { "codepoints": [10914, 824], "characters": "\u2AA2\u0338" }, - "⪡̸": { "codepoints": [10913, 824], "characters": "\u2AA1\u0338" }, - "⊀": { "codepoints": [8832], "characters": "\u2280" }, - "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, - "⋠": { "codepoints": [8928], "characters": "\u22E0" }, - "∌": { "codepoints": [8716], "characters": "\u220C" }, - "⋫": { "codepoints": [8939], "characters": "\u22EB" }, - "⧐̸": { "codepoints": [10704, 824], "characters": "\u29D0\u0338" }, - "⋭": { "codepoints": [8941], "characters": "\u22ED" }, - "⊏̸": { "codepoints": [8847, 824], "characters": "\u228F\u0338" }, - "⋢": { "codepoints": [8930], "characters": "\u22E2" }, - "⊐̸": { "codepoints": [8848, 824], "characters": "\u2290\u0338" }, - "⋣": { "codepoints": [8931], "characters": "\u22E3" }, - "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, - "⊈": { "codepoints": [8840], "characters": "\u2288" }, - "⊁": { "codepoints": [8833], "characters": "\u2281" }, - "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, - "⋡": { "codepoints": [8929], "characters": "\u22E1" }, - "≿̸": { "codepoints": [8831, 824], "characters": "\u227F\u0338" }, - "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, - "⊉": { "codepoints": [8841], "characters": "\u2289" }, - "≁": { "codepoints": [8769], "characters": "\u2241" }, - "≄": { "codepoints": [8772], "characters": "\u2244" }, - "≇": { "codepoints": [8775], "characters": "\u2247" }, - "≉": { "codepoints": [8777], "characters": "\u2249" }, - "∤": { "codepoints": [8740], "characters": "\u2224" }, - "𝒩": { "codepoints": [119977], "characters": "\uD835\uDCA9" }, - "Ñ": { "codepoints": [209], "characters": "\u00D1" }, - "Ñ": { "codepoints": [209], "characters": "\u00D1" }, - "Ν": { "codepoints": [925], "characters": "\u039D" }, - "Œ": { "codepoints": [338], "characters": "\u0152" }, - "Ó": { "codepoints": [211], "characters": "\u00D3" }, - "Ó": { "codepoints": [211], "characters": "\u00D3" }, - "Ô": { "codepoints": [212], "characters": "\u00D4" }, - "Ô": { "codepoints": [212], "characters": "\u00D4" }, - "О": { "codepoints": [1054], "characters": "\u041E" }, - "Ő": { "codepoints": [336], "characters": "\u0150" }, - "𝔒": { "codepoints": [120082], "characters": "\uD835\uDD12" }, - "Ò": { "codepoints": [210], "characters": "\u00D2" }, - "Ò": { "codepoints": [210], "characters": "\u00D2" }, - "Ō": { "codepoints": [332], "characters": "\u014C" }, - "Ω": { "codepoints": [937], "characters": "\u03A9" }, - "Ο": { "codepoints": [927], "characters": "\u039F" }, - "𝕆": { "codepoints": [120134], "characters": "\uD835\uDD46" }, - "“": { "codepoints": [8220], "characters": "\u201C" }, - "‘": { "codepoints": [8216], "characters": "\u2018" }, - "⩔": { "codepoints": [10836], "characters": "\u2A54" }, - "𝒪": { "codepoints": [119978], "characters": "\uD835\uDCAA" }, - "Ø": { "codepoints": [216], "characters": "\u00D8" }, - "Ø": { "codepoints": [216], "characters": "\u00D8" }, - "Õ": { "codepoints": [213], "characters": "\u00D5" }, - "Õ": { "codepoints": [213], "characters": "\u00D5" }, - "⨷": { "codepoints": [10807], "characters": "\u2A37" }, - "Ö": { "codepoints": [214], "characters": "\u00D6" }, - "Ö": { "codepoints": [214], "characters": "\u00D6" }, - "‾": { "codepoints": [8254], "characters": "\u203E" }, - "⏞": { "codepoints": [9182], "characters": "\u23DE" }, - "⎴": { "codepoints": [9140], "characters": "\u23B4" }, - "⏜": { "codepoints": [9180], "characters": "\u23DC" }, - "∂": { "codepoints": [8706], "characters": "\u2202" }, - "П": { "codepoints": [1055], "characters": "\u041F" }, - "𝔓": { "codepoints": [120083], "characters": "\uD835\uDD13" }, - "Φ": { "codepoints": [934], "characters": "\u03A6" }, - "Π": { "codepoints": [928], "characters": "\u03A0" }, - "±": { "codepoints": [177], "characters": "\u00B1" }, - "ℌ": { "codepoints": [8460], "characters": "\u210C" }, - "ℙ": { "codepoints": [8473], "characters": "\u2119" }, - "⪻": { "codepoints": [10939], "characters": "\u2ABB" }, - "≺": { "codepoints": [8826], "characters": "\u227A" }, - "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, - "≼": { "codepoints": [8828], "characters": "\u227C" }, - "≾": { "codepoints": [8830], "characters": "\u227E" }, - "″": { "codepoints": [8243], "characters": "\u2033" }, - "∏": { "codepoints": [8719], "characters": "\u220F" }, - "∷": { "codepoints": [8759], "characters": "\u2237" }, - "∝": { "codepoints": [8733], "characters": "\u221D" }, - "𝒫": { "codepoints": [119979], "characters": "\uD835\uDCAB" }, - "Ψ": { "codepoints": [936], "characters": "\u03A8" }, - """: { "codepoints": [34], "characters": "\u0022" }, - """: { "codepoints": [34], "characters": "\u0022" }, - "𝔔": { "codepoints": [120084], "characters": "\uD835\uDD14" }, - "ℚ": { "codepoints": [8474], "characters": "\u211A" }, - "𝒬": { "codepoints": [119980], "characters": "\uD835\uDCAC" }, - "⤐": { "codepoints": [10512], "characters": "\u2910" }, - "®": { "codepoints": [174], "characters": "\u00AE" }, - "®": { "codepoints": [174], "characters": "\u00AE" }, - "Ŕ": { "codepoints": [340], "characters": "\u0154" }, - "⟫": { "codepoints": [10219], "characters": "\u27EB" }, - "↠": { "codepoints": [8608], "characters": "\u21A0" }, - "⤖": { "codepoints": [10518], "characters": "\u2916" }, - "Ř": { "codepoints": [344], "characters": "\u0158" }, - "Ŗ": { "codepoints": [342], "characters": "\u0156" }, - "Р": { "codepoints": [1056], "characters": "\u0420" }, - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, - "∋": { "codepoints": [8715], "characters": "\u220B" }, - "⇋": { "codepoints": [8651], "characters": "\u21CB" }, - "⥯": { "codepoints": [10607], "characters": "\u296F" }, - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, - "Ρ": { "codepoints": [929], "characters": "\u03A1" }, - "⟩": { "codepoints": [10217], "characters": "\u27E9" }, - "→": { "codepoints": [8594], "characters": "\u2192" }, - "⇥": { "codepoints": [8677], "characters": "\u21E5" }, - "⇄": { "codepoints": [8644], "characters": "\u21C4" }, - "⌉": { "codepoints": [8969], "characters": "\u2309" }, - "⟧": { "codepoints": [10215], "characters": "\u27E7" }, - "⥝": { "codepoints": [10589], "characters": "\u295D" }, - "⇂": { "codepoints": [8642], "characters": "\u21C2" }, - "⥕": { "codepoints": [10581], "characters": "\u2955" }, - "⌋": { "codepoints": [8971], "characters": "\u230B" }, - "⊢": { "codepoints": [8866], "characters": "\u22A2" }, - "↦": { "codepoints": [8614], "characters": "\u21A6" }, - "⥛": { "codepoints": [10587], "characters": "\u295B" }, - "⊳": { "codepoints": [8883], "characters": "\u22B3" }, - "⧐": { "codepoints": [10704], "characters": "\u29D0" }, - "⊵": { "codepoints": [8885], "characters": "\u22B5" }, - "⥏": { "codepoints": [10575], "characters": "\u294F" }, - "⥜": { "codepoints": [10588], "characters": "\u295C" }, - "↾": { "codepoints": [8638], "characters": "\u21BE" }, - "⥔": { "codepoints": [10580], "characters": "\u2954" }, - "⇀": { "codepoints": [8640], "characters": "\u21C0" }, - "⥓": { "codepoints": [10579], "characters": "\u2953" }, - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, - "ℝ": { "codepoints": [8477], "characters": "\u211D" }, - "⥰": { "codepoints": [10608], "characters": "\u2970" }, - "⇛": { "codepoints": [8667], "characters": "\u21DB" }, - "ℛ": { "codepoints": [8475], "characters": "\u211B" }, - "↱": { "codepoints": [8625], "characters": "\u21B1" }, - "⧴": { "codepoints": [10740], "characters": "\u29F4" }, - "Щ": { "codepoints": [1065], "characters": "\u0429" }, - "Ш": { "codepoints": [1064], "characters": "\u0428" }, - "Ь": { "codepoints": [1068], "characters": "\u042C" }, - "Ś": { "codepoints": [346], "characters": "\u015A" }, - "⪼": { "codepoints": [10940], "characters": "\u2ABC" }, - "Š": { "codepoints": [352], "characters": "\u0160" }, - "Ş": { "codepoints": [350], "characters": "\u015E" }, - "Ŝ": { "codepoints": [348], "characters": "\u015C" }, - "С": { "codepoints": [1057], "characters": "\u0421" }, - "𝔖": { "codepoints": [120086], "characters": "\uD835\uDD16" }, - "↓": { "codepoints": [8595], "characters": "\u2193" }, - "←": { "codepoints": [8592], "characters": "\u2190" }, - "→": { "codepoints": [8594], "characters": "\u2192" }, - "↑": { "codepoints": [8593], "characters": "\u2191" }, - "Σ": { "codepoints": [931], "characters": "\u03A3" }, - "∘": { "codepoints": [8728], "characters": "\u2218" }, - "𝕊": { "codepoints": [120138], "characters": "\uD835\uDD4A" }, - "√": { "codepoints": [8730], "characters": "\u221A" }, - "□": { "codepoints": [9633], "characters": "\u25A1" }, - "⊓": { "codepoints": [8851], "characters": "\u2293" }, - "⊏": { "codepoints": [8847], "characters": "\u228F" }, - "⊑": { "codepoints": [8849], "characters": "\u2291" }, - "⊐": { "codepoints": [8848], "characters": "\u2290" }, - "⊒": { "codepoints": [8850], "characters": "\u2292" }, - "⊔": { "codepoints": [8852], "characters": "\u2294" }, - "𝒮": { "codepoints": [119982], "characters": "\uD835\uDCAE" }, - "⋆": { "codepoints": [8902], "characters": "\u22C6" }, - "⋐": { "codepoints": [8912], "characters": "\u22D0" }, - "⋐": { "codepoints": [8912], "characters": "\u22D0" }, - "⊆": { "codepoints": [8838], "characters": "\u2286" }, - "≻": { "codepoints": [8827], "characters": "\u227B" }, - "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, - "≽": { "codepoints": [8829], "characters": "\u227D" }, - "≿": { "codepoints": [8831], "characters": "\u227F" }, - "∋": { "codepoints": [8715], "characters": "\u220B" }, - "∑": { "codepoints": [8721], "characters": "\u2211" }, - "⋑": { "codepoints": [8913], "characters": "\u22D1" }, - "⊃": { "codepoints": [8835], "characters": "\u2283" }, - "⊇": { "codepoints": [8839], "characters": "\u2287" }, - "⋑": { "codepoints": [8913], "characters": "\u22D1" }, - "Þ": { "codepoints": [222], "characters": "\u00DE" }, - "Þ": { "codepoints": [222], "characters": "\u00DE" }, - "™": { "codepoints": [8482], "characters": "\u2122" }, - "Ћ": { "codepoints": [1035], "characters": "\u040B" }, - "Ц": { "codepoints": [1062], "characters": "\u0426" }, - " ": { "codepoints": [9], "characters": "\u0009" }, - "Τ": { "codepoints": [932], "characters": "\u03A4" }, - "Ť": { "codepoints": [356], "characters": "\u0164" }, - "Ţ": { "codepoints": [354], "characters": "\u0162" }, - "Т": { "codepoints": [1058], "characters": "\u0422" }, - "𝔗": { "codepoints": [120087], "characters": "\uD835\uDD17" }, - "∴": { "codepoints": [8756], "characters": "\u2234" }, - "Θ": { "codepoints": [920], "characters": "\u0398" }, - "  ": { "codepoints": [8287, 8202], "characters": "\u205F\u200A" }, - " ": { "codepoints": [8201], "characters": "\u2009" }, - "∼": { "codepoints": [8764], "characters": "\u223C" }, - "≃": { "codepoints": [8771], "characters": "\u2243" }, - "≅": { "codepoints": [8773], "characters": "\u2245" }, - "≈": { "codepoints": [8776], "characters": "\u2248" }, - "𝕋": { "codepoints": [120139], "characters": "\uD835\uDD4B" }, - "⃛": { "codepoints": [8411], "characters": "\u20DB" }, - "𝒯": { "codepoints": [119983], "characters": "\uD835\uDCAF" }, - "Ŧ": { "codepoints": [358], "characters": "\u0166" }, - "Ú": { "codepoints": [218], "characters": "\u00DA" }, - "Ú": { "codepoints": [218], "characters": "\u00DA" }, - "↟": { "codepoints": [8607], "characters": "\u219F" }, - "⥉": { "codepoints": [10569], "characters": "\u2949" }, - "Ў": { "codepoints": [1038], "characters": "\u040E" }, - "Ŭ": { "codepoints": [364], "characters": "\u016C" }, - "Û": { "codepoints": [219], "characters": "\u00DB" }, - "Û": { "codepoints": [219], "characters": "\u00DB" }, - "У": { "codepoints": [1059], "characters": "\u0423" }, - "Ű": { "codepoints": [368], "characters": "\u0170" }, - "𝔘": { "codepoints": [120088], "characters": "\uD835\uDD18" }, - "Ù": { "codepoints": [217], "characters": "\u00D9" }, - "Ù": { "codepoints": [217], "characters": "\u00D9" }, - "Ū": { "codepoints": [362], "characters": "\u016A" }, - "_": { "codepoints": [95], "characters": "\u005F" }, - "⏟": { "codepoints": [9183], "characters": "\u23DF" }, - "⎵": { "codepoints": [9141], "characters": "\u23B5" }, - "⏝": { "codepoints": [9181], "characters": "\u23DD" }, - "⋃": { "codepoints": [8899], "characters": "\u22C3" }, - "⊎": { "codepoints": [8846], "characters": "\u228E" }, - "Ų": { "codepoints": [370], "characters": "\u0172" }, - "𝕌": { "codepoints": [120140], "characters": "\uD835\uDD4C" }, - "↑": { "codepoints": [8593], "characters": "\u2191" }, - "⤒": { "codepoints": [10514], "characters": "\u2912" }, - "⇅": { "codepoints": [8645], "characters": "\u21C5" }, - "↕": { "codepoints": [8597], "characters": "\u2195" }, - "⥮": { "codepoints": [10606], "characters": "\u296E" }, - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, - "↥": { "codepoints": [8613], "characters": "\u21A5" }, - "⇑": { "codepoints": [8657], "characters": "\u21D1" }, - "⇕": { "codepoints": [8661], "characters": "\u21D5" }, - "↖": { "codepoints": [8598], "characters": "\u2196" }, - "↗": { "codepoints": [8599], "characters": "\u2197" }, - "ϒ": { "codepoints": [978], "characters": "\u03D2" }, - "Υ": { "codepoints": [933], "characters": "\u03A5" }, - "Ů": { "codepoints": [366], "characters": "\u016E" }, - "𝒰": { "codepoints": [119984], "characters": "\uD835\uDCB0" }, - "Ũ": { "codepoints": [360], "characters": "\u0168" }, - "Ü": { "codepoints": [220], "characters": "\u00DC" }, - "Ü": { "codepoints": [220], "characters": "\u00DC" }, - "⊫": { "codepoints": [8875], "characters": "\u22AB" }, - "⫫": { "codepoints": [10987], "characters": "\u2AEB" }, - "В": { "codepoints": [1042], "characters": "\u0412" }, - "⊩": { "codepoints": [8873], "characters": "\u22A9" }, - "⫦": { "codepoints": [10982], "characters": "\u2AE6" }, - "⋁": { "codepoints": [8897], "characters": "\u22C1" }, - "‖": { "codepoints": [8214], "characters": "\u2016" }, - "‖": { "codepoints": [8214], "characters": "\u2016" }, - "∣": { "codepoints": [8739], "characters": "\u2223" }, - "|": { "codepoints": [124], "characters": "\u007C" }, - "❘": { "codepoints": [10072], "characters": "\u2758" }, - "≀": { "codepoints": [8768], "characters": "\u2240" }, - " ": { "codepoints": [8202], "characters": "\u200A" }, - "𝔙": { "codepoints": [120089], "characters": "\uD835\uDD19" }, - "𝕍": { "codepoints": [120141], "characters": "\uD835\uDD4D" }, - "𝒱": { "codepoints": [119985], "characters": "\uD835\uDCB1" }, - "⊪": { "codepoints": [8874], "characters": "\u22AA" }, - "Ŵ": { "codepoints": [372], "characters": "\u0174" }, - "⋀": { "codepoints": [8896], "characters": "\u22C0" }, - "𝔚": { "codepoints": [120090], "characters": "\uD835\uDD1A" }, - "𝕎": { "codepoints": [120142], "characters": "\uD835\uDD4E" }, - "𝒲": { "codepoints": [119986], "characters": "\uD835\uDCB2" }, - "𝔛": { "codepoints": [120091], "characters": "\uD835\uDD1B" }, - "Ξ": { "codepoints": [926], "characters": "\u039E" }, - "𝕏": { "codepoints": [120143], "characters": "\uD835\uDD4F" }, - "𝒳": { "codepoints": [119987], "characters": "\uD835\uDCB3" }, - "Я": { "codepoints": [1071], "characters": "\u042F" }, - "Ї": { "codepoints": [1031], "characters": "\u0407" }, - "Ю": { "codepoints": [1070], "characters": "\u042E" }, - "Ý": { "codepoints": [221], "characters": "\u00DD" }, - "Ý": { "codepoints": [221], "characters": "\u00DD" }, - "Ŷ": { "codepoints": [374], "characters": "\u0176" }, - "Ы": { "codepoints": [1067], "characters": "\u042B" }, - "𝔜": { "codepoints": [120092], "characters": "\uD835\uDD1C" }, - "𝕐": { "codepoints": [120144], "characters": "\uD835\uDD50" }, - "𝒴": { "codepoints": [119988], "characters": "\uD835\uDCB4" }, - "Ÿ": { "codepoints": [376], "characters": "\u0178" }, - "Ж": { "codepoints": [1046], "characters": "\u0416" }, - "Ź": { "codepoints": [377], "characters": "\u0179" }, - "Ž": { "codepoints": [381], "characters": "\u017D" }, - "З": { "codepoints": [1047], "characters": "\u0417" }, - "Ż": { "codepoints": [379], "characters": "\u017B" }, - "​": { "codepoints": [8203], "characters": "\u200B" }, - "Ζ": { "codepoints": [918], "characters": "\u0396" }, - "ℨ": { "codepoints": [8488], "characters": "\u2128" }, - "ℤ": { "codepoints": [8484], "characters": "\u2124" }, - "𝒵": { "codepoints": [119989], "characters": "\uD835\uDCB5" }, - "á": { "codepoints": [225], "characters": "\u00E1" }, - "á": { "codepoints": [225], "characters": "\u00E1" }, - "ă": { "codepoints": [259], "characters": "\u0103" }, - "∾": { "codepoints": [8766], "characters": "\u223E" }, - "∾̳": { "codepoints": [8766, 819], "characters": "\u223E\u0333" }, - "∿": { "codepoints": [8767], "characters": "\u223F" }, - "â": { "codepoints": [226], "characters": "\u00E2" }, - "â": { "codepoints": [226], "characters": "\u00E2" }, - "´": { "codepoints": [180], "characters": "\u00B4" }, - "´": { "codepoints": [180], "characters": "\u00B4" }, - "а": { "codepoints": [1072], "characters": "\u0430" }, - "æ": { "codepoints": [230], "characters": "\u00E6" }, - "æ": { "codepoints": [230], "characters": "\u00E6" }, - "⁡": { "codepoints": [8289], "characters": "\u2061" }, - "𝔞": { "codepoints": [120094], "characters": "\uD835\uDD1E" }, - "à": { "codepoints": [224], "characters": "\u00E0" }, - "à": { "codepoints": [224], "characters": "\u00E0" }, - "ℵ": { "codepoints": [8501], "characters": "\u2135" }, - "ℵ": { "codepoints": [8501], "characters": "\u2135" }, - "α": { "codepoints": [945], "characters": "\u03B1" }, - "ā": { "codepoints": [257], "characters": "\u0101" }, - "⨿": { "codepoints": [10815], "characters": "\u2A3F" }, - "&": { "codepoints": [38], "characters": "\u0026" }, - "&": { "codepoints": [38], "characters": "\u0026" }, - "∧": { "codepoints": [8743], "characters": "\u2227" }, - "⩕": { "codepoints": [10837], "characters": "\u2A55" }, - "⩜": { "codepoints": [10844], "characters": "\u2A5C" }, - "⩘": { "codepoints": [10840], "characters": "\u2A58" }, - "⩚": { "codepoints": [10842], "characters": "\u2A5A" }, - "∠": { "codepoints": [8736], "characters": "\u2220" }, - "⦤": { "codepoints": [10660], "characters": "\u29A4" }, - "∠": { "codepoints": [8736], "characters": "\u2220" }, - "∡": { "codepoints": [8737], "characters": "\u2221" }, - "⦨": { "codepoints": [10664], "characters": "\u29A8" }, - "⦩": { "codepoints": [10665], "characters": "\u29A9" }, - "⦪": { "codepoints": [10666], "characters": "\u29AA" }, - "⦫": { "codepoints": [10667], "characters": "\u29AB" }, - "⦬": { "codepoints": [10668], "characters": "\u29AC" }, - "⦭": { "codepoints": [10669], "characters": "\u29AD" }, - "⦮": { "codepoints": [10670], "characters": "\u29AE" }, - "⦯": { "codepoints": [10671], "characters": "\u29AF" }, - "∟": { "codepoints": [8735], "characters": "\u221F" }, - "⊾": { "codepoints": [8894], "characters": "\u22BE" }, - "⦝": { "codepoints": [10653], "characters": "\u299D" }, - "∢": { "codepoints": [8738], "characters": "\u2222" }, - "Å": { "codepoints": [197], "characters": "\u00C5" }, - "⍼": { "codepoints": [9084], "characters": "\u237C" }, - "ą": { "codepoints": [261], "characters": "\u0105" }, - "𝕒": { "codepoints": [120146], "characters": "\uD835\uDD52" }, - "≈": { "codepoints": [8776], "characters": "\u2248" }, - "⩰": { "codepoints": [10864], "characters": "\u2A70" }, - "⩯": { "codepoints": [10863], "characters": "\u2A6F" }, - "≊": { "codepoints": [8778], "characters": "\u224A" }, - "≋": { "codepoints": [8779], "characters": "\u224B" }, - "'": { "codepoints": [39], "characters": "\u0027" }, - "≈": { "codepoints": [8776], "characters": "\u2248" }, - "≊": { "codepoints": [8778], "characters": "\u224A" }, - "å": { "codepoints": [229], "characters": "\u00E5" }, - "å": { "codepoints": [229], "characters": "\u00E5" }, - "𝒶": { "codepoints": [119990], "characters": "\uD835\uDCB6" }, - "*": { "codepoints": [42], "characters": "\u002A" }, - "≈": { "codepoints": [8776], "characters": "\u2248" }, - "≍": { "codepoints": [8781], "characters": "\u224D" }, - "ã": { "codepoints": [227], "characters": "\u00E3" }, - "ã": { "codepoints": [227], "characters": "\u00E3" }, - "ä": { "codepoints": [228], "characters": "\u00E4" }, - "ä": { "codepoints": [228], "characters": "\u00E4" }, - "∳": { "codepoints": [8755], "characters": "\u2233" }, - "⨑": { "codepoints": [10769], "characters": "\u2A11" }, - "⫭": { "codepoints": [10989], "characters": "\u2AED" }, - "≌": { "codepoints": [8780], "characters": "\u224C" }, - "϶": { "codepoints": [1014], "characters": "\u03F6" }, - "‵": { "codepoints": [8245], "characters": "\u2035" }, - "∽": { "codepoints": [8765], "characters": "\u223D" }, - "⋍": { "codepoints": [8909], "characters": "\u22CD" }, - "⊽": { "codepoints": [8893], "characters": "\u22BD" }, - "⌅": { "codepoints": [8965], "characters": "\u2305" }, - "⌅": { "codepoints": [8965], "characters": "\u2305" }, - "⎵": { "codepoints": [9141], "characters": "\u23B5" }, - "⎶": { "codepoints": [9142], "characters": "\u23B6" }, - "≌": { "codepoints": [8780], "characters": "\u224C" }, - "б": { "codepoints": [1073], "characters": "\u0431" }, - "„": { "codepoints": [8222], "characters": "\u201E" }, - "∵": { "codepoints": [8757], "characters": "\u2235" }, - "∵": { "codepoints": [8757], "characters": "\u2235" }, - "⦰": { "codepoints": [10672], "characters": "\u29B0" }, - "϶": { "codepoints": [1014], "characters": "\u03F6" }, - "ℬ": { "codepoints": [8492], "characters": "\u212C" }, - "β": { "codepoints": [946], "characters": "\u03B2" }, - "ℶ": { "codepoints": [8502], "characters": "\u2136" }, - "≬": { "codepoints": [8812], "characters": "\u226C" }, - "𝔟": { "codepoints": [120095], "characters": "\uD835\uDD1F" }, - "⋂": { "codepoints": [8898], "characters": "\u22C2" }, - "◯": { "codepoints": [9711], "characters": "\u25EF" }, - "⋃": { "codepoints": [8899], "characters": "\u22C3" }, - "⨀": { "codepoints": [10752], "characters": "\u2A00" }, - "⨁": { "codepoints": [10753], "characters": "\u2A01" }, - "⨂": { "codepoints": [10754], "characters": "\u2A02" }, - "⨆": { "codepoints": [10758], "characters": "\u2A06" }, - "★": { "codepoints": [9733], "characters": "\u2605" }, - "▽": { "codepoints": [9661], "characters": "\u25BD" }, - "△": { "codepoints": [9651], "characters": "\u25B3" }, - "⨄": { "codepoints": [10756], "characters": "\u2A04" }, - "⋁": { "codepoints": [8897], "characters": "\u22C1" }, - "⋀": { "codepoints": [8896], "characters": "\u22C0" }, - "⤍": { "codepoints": [10509], "characters": "\u290D" }, - "⧫": { "codepoints": [10731], "characters": "\u29EB" }, - "▪": { "codepoints": [9642], "characters": "\u25AA" }, - "▴": { "codepoints": [9652], "characters": "\u25B4" }, - "▾": { "codepoints": [9662], "characters": "\u25BE" }, - "◂": { "codepoints": [9666], "characters": "\u25C2" }, - "▸": { "codepoints": [9656], "characters": "\u25B8" }, - "␣": { "codepoints": [9251], "characters": "\u2423" }, - "▒": { "codepoints": [9618], "characters": "\u2592" }, - "░": { "codepoints": [9617], "characters": "\u2591" }, - "▓": { "codepoints": [9619], "characters": "\u2593" }, - "█": { "codepoints": [9608], "characters": "\u2588" }, - "=⃥": { "codepoints": [61, 8421], "characters": "\u003D\u20E5" }, - "≡⃥": { "codepoints": [8801, 8421], "characters": "\u2261\u20E5" }, - "⌐": { "codepoints": [8976], "characters": "\u2310" }, - "𝕓": { "codepoints": [120147], "characters": "\uD835\uDD53" }, - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, - "⋈": { "codepoints": [8904], "characters": "\u22C8" }, - "╗": { "codepoints": [9559], "characters": "\u2557" }, - "╔": { "codepoints": [9556], "characters": "\u2554" }, - "╖": { "codepoints": [9558], "characters": "\u2556" }, - "╓": { "codepoints": [9555], "characters": "\u2553" }, - "═": { "codepoints": [9552], "characters": "\u2550" }, - "╦": { "codepoints": [9574], "characters": "\u2566" }, - "╩": { "codepoints": [9577], "characters": "\u2569" }, - "╤": { "codepoints": [9572], "characters": "\u2564" }, - "╧": { "codepoints": [9575], "characters": "\u2567" }, - "╝": { "codepoints": [9565], "characters": "\u255D" }, - "╚": { "codepoints": [9562], "characters": "\u255A" }, - "╜": { "codepoints": [9564], "characters": "\u255C" }, - "╙": { "codepoints": [9561], "characters": "\u2559" }, - "║": { "codepoints": [9553], "characters": "\u2551" }, - "╬": { "codepoints": [9580], "characters": "\u256C" }, - "╣": { "codepoints": [9571], "characters": "\u2563" }, - "╠": { "codepoints": [9568], "characters": "\u2560" }, - "╫": { "codepoints": [9579], "characters": "\u256B" }, - "╢": { "codepoints": [9570], "characters": "\u2562" }, - "╟": { "codepoints": [9567], "characters": "\u255F" }, - "⧉": { "codepoints": [10697], "characters": "\u29C9" }, - "╕": { "codepoints": [9557], "characters": "\u2555" }, - "╒": { "codepoints": [9554], "characters": "\u2552" }, - "┐": { "codepoints": [9488], "characters": "\u2510" }, - "┌": { "codepoints": [9484], "characters": "\u250C" }, - "─": { "codepoints": [9472], "characters": "\u2500" }, - "╥": { "codepoints": [9573], "characters": "\u2565" }, - "╨": { "codepoints": [9576], "characters": "\u2568" }, - "┬": { "codepoints": [9516], "characters": "\u252C" }, - "┴": { "codepoints": [9524], "characters": "\u2534" }, - "⊟": { "codepoints": [8863], "characters": "\u229F" }, - "⊞": { "codepoints": [8862], "characters": "\u229E" }, - "⊠": { "codepoints": [8864], "characters": "\u22A0" }, - "╛": { "codepoints": [9563], "characters": "\u255B" }, - "╘": { "codepoints": [9560], "characters": "\u2558" }, - "┘": { "codepoints": [9496], "characters": "\u2518" }, - "└": { "codepoints": [9492], "characters": "\u2514" }, - "│": { "codepoints": [9474], "characters": "\u2502" }, - "╪": { "codepoints": [9578], "characters": "\u256A" }, - "╡": { "codepoints": [9569], "characters": "\u2561" }, - "╞": { "codepoints": [9566], "characters": "\u255E" }, - "┼": { "codepoints": [9532], "characters": "\u253C" }, - "┤": { "codepoints": [9508], "characters": "\u2524" }, - "├": { "codepoints": [9500], "characters": "\u251C" }, - "‵": { "codepoints": [8245], "characters": "\u2035" }, - "˘": { "codepoints": [728], "characters": "\u02D8" }, - "¦": { "codepoints": [166], "characters": "\u00A6" }, - "¦": { "codepoints": [166], "characters": "\u00A6" }, - "𝒷": { "codepoints": [119991], "characters": "\uD835\uDCB7" }, - "⁏": { "codepoints": [8271], "characters": "\u204F" }, - "∽": { "codepoints": [8765], "characters": "\u223D" }, - "⋍": { "codepoints": [8909], "characters": "\u22CD" }, - "\": { "codepoints": [92], "characters": "\u005C" }, - "⧅": { "codepoints": [10693], "characters": "\u29C5" }, - "⟈": { "codepoints": [10184], "characters": "\u27C8" }, - "•": { "codepoints": [8226], "characters": "\u2022" }, - "•": { "codepoints": [8226], "characters": "\u2022" }, - "≎": { "codepoints": [8782], "characters": "\u224E" }, - "⪮": { "codepoints": [10926], "characters": "\u2AAE" }, - "≏": { "codepoints": [8783], "characters": "\u224F" }, - "≏": { "codepoints": [8783], "characters": "\u224F" }, - "ć": { "codepoints": [263], "characters": "\u0107" }, - "∩": { "codepoints": [8745], "characters": "\u2229" }, - "⩄": { "codepoints": [10820], "characters": "\u2A44" }, - "⩉": { "codepoints": [10825], "characters": "\u2A49" }, - "⩋": { "codepoints": [10827], "characters": "\u2A4B" }, - "⩇": { "codepoints": [10823], "characters": "\u2A47" }, - "⩀": { "codepoints": [10816], "characters": "\u2A40" }, - "∩︀": { "codepoints": [8745, 65024], "characters": "\u2229\uFE00" }, - "⁁": { "codepoints": [8257], "characters": "\u2041" }, - "ˇ": { "codepoints": [711], "characters": "\u02C7" }, - "⩍": { "codepoints": [10829], "characters": "\u2A4D" }, - "č": { "codepoints": [269], "characters": "\u010D" }, - "ç": { "codepoints": [231], "characters": "\u00E7" }, - "ç": { "codepoints": [231], "characters": "\u00E7" }, - "ĉ": { "codepoints": [265], "characters": "\u0109" }, - "⩌": { "codepoints": [10828], "characters": "\u2A4C" }, - "⩐": { "codepoints": [10832], "characters": "\u2A50" }, - "ċ": { "codepoints": [267], "characters": "\u010B" }, - "¸": { "codepoints": [184], "characters": "\u00B8" }, - "¸": { "codepoints": [184], "characters": "\u00B8" }, - "⦲": { "codepoints": [10674], "characters": "\u29B2" }, - "¢": { "codepoints": [162], "characters": "\u00A2" }, - "¢": { "codepoints": [162], "characters": "\u00A2" }, - "·": { "codepoints": [183], "characters": "\u00B7" }, - "𝔠": { "codepoints": [120096], "characters": "\uD835\uDD20" }, - "ч": { "codepoints": [1095], "characters": "\u0447" }, - "✓": { "codepoints": [10003], "characters": "\u2713" }, - "✓": { "codepoints": [10003], "characters": "\u2713" }, - "χ": { "codepoints": [967], "characters": "\u03C7" }, - "○": { "codepoints": [9675], "characters": "\u25CB" }, - "⧃": { "codepoints": [10691], "characters": "\u29C3" }, - "ˆ": { "codepoints": [710], "characters": "\u02C6" }, - "≗": { "codepoints": [8791], "characters": "\u2257" }, - "↺": { "codepoints": [8634], "characters": "\u21BA" }, - "↻": { "codepoints": [8635], "characters": "\u21BB" }, - "®": { "codepoints": [174], "characters": "\u00AE" }, - "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, - "⊛": { "codepoints": [8859], "characters": "\u229B" }, - "⊚": { "codepoints": [8858], "characters": "\u229A" }, - "⊝": { "codepoints": [8861], "characters": "\u229D" }, - "≗": { "codepoints": [8791], "characters": "\u2257" }, - "⨐": { "codepoints": [10768], "characters": "\u2A10" }, - "⫯": { "codepoints": [10991], "characters": "\u2AEF" }, - "⧂": { "codepoints": [10690], "characters": "\u29C2" }, - "♣": { "codepoints": [9827], "characters": "\u2663" }, - "♣": { "codepoints": [9827], "characters": "\u2663" }, - ":": { "codepoints": [58], "characters": "\u003A" }, - "≔": { "codepoints": [8788], "characters": "\u2254" }, - "≔": { "codepoints": [8788], "characters": "\u2254" }, - ",": { "codepoints": [44], "characters": "\u002C" }, - "@": { "codepoints": [64], "characters": "\u0040" }, - "∁": { "codepoints": [8705], "characters": "\u2201" }, - "∘": { "codepoints": [8728], "characters": "\u2218" }, - "∁": { "codepoints": [8705], "characters": "\u2201" }, - "ℂ": { "codepoints": [8450], "characters": "\u2102" }, - "≅": { "codepoints": [8773], "characters": "\u2245" }, - "⩭": { "codepoints": [10861], "characters": "\u2A6D" }, - "∮": { "codepoints": [8750], "characters": "\u222E" }, - "𝕔": { "codepoints": [120148], "characters": "\uD835\uDD54" }, - "∐": { "codepoints": [8720], "characters": "\u2210" }, - "©": { "codepoints": [169], "characters": "\u00A9" }, - "©": { "codepoints": [169], "characters": "\u00A9" }, - "℗": { "codepoints": [8471], "characters": "\u2117" }, - "↵": { "codepoints": [8629], "characters": "\u21B5" }, - "✗": { "codepoints": [10007], "characters": "\u2717" }, - "𝒸": { "codepoints": [119992], "characters": "\uD835\uDCB8" }, - "⫏": { "codepoints": [10959], "characters": "\u2ACF" }, - "⫑": { "codepoints": [10961], "characters": "\u2AD1" }, - "⫐": { "codepoints": [10960], "characters": "\u2AD0" }, - "⫒": { "codepoints": [10962], "characters": "\u2AD2" }, - "⋯": { "codepoints": [8943], "characters": "\u22EF" }, - "⤸": { "codepoints": [10552], "characters": "\u2938" }, - "⤵": { "codepoints": [10549], "characters": "\u2935" }, - "⋞": { "codepoints": [8926], "characters": "\u22DE" }, - "⋟": { "codepoints": [8927], "characters": "\u22DF" }, - "↶": { "codepoints": [8630], "characters": "\u21B6" }, - "⤽": { "codepoints": [10557], "characters": "\u293D" }, - "∪": { "codepoints": [8746], "characters": "\u222A" }, - "⩈": { "codepoints": [10824], "characters": "\u2A48" }, - "⩆": { "codepoints": [10822], "characters": "\u2A46" }, - "⩊": { "codepoints": [10826], "characters": "\u2A4A" }, - "⊍": { "codepoints": [8845], "characters": "\u228D" }, - "⩅": { "codepoints": [10821], "characters": "\u2A45" }, - "∪︀": { "codepoints": [8746, 65024], "characters": "\u222A\uFE00" }, - "↷": { "codepoints": [8631], "characters": "\u21B7" }, - "⤼": { "codepoints": [10556], "characters": "\u293C" }, - "⋞": { "codepoints": [8926], "characters": "\u22DE" }, - "⋟": { "codepoints": [8927], "characters": "\u22DF" }, - "⋎": { "codepoints": [8910], "characters": "\u22CE" }, - "⋏": { "codepoints": [8911], "characters": "\u22CF" }, - "¤": { "codepoints": [164], "characters": "\u00A4" }, - "¤": { "codepoints": [164], "characters": "\u00A4" }, - "↶": { "codepoints": [8630], "characters": "\u21B6" }, - "↷": { "codepoints": [8631], "characters": "\u21B7" }, - "⋎": { "codepoints": [8910], "characters": "\u22CE" }, - "⋏": { "codepoints": [8911], "characters": "\u22CF" }, - "∲": { "codepoints": [8754], "characters": "\u2232" }, - "∱": { "codepoints": [8753], "characters": "\u2231" }, - "⌭": { "codepoints": [9005], "characters": "\u232D" }, - "⇓": { "codepoints": [8659], "characters": "\u21D3" }, - "⥥": { "codepoints": [10597], "characters": "\u2965" }, - "†": { "codepoints": [8224], "characters": "\u2020" }, - "ℸ": { "codepoints": [8504], "characters": "\u2138" }, - "↓": { "codepoints": [8595], "characters": "\u2193" }, - "‐": { "codepoints": [8208], "characters": "\u2010" }, - "⊣": { "codepoints": [8867], "characters": "\u22A3" }, - "⤏": { "codepoints": [10511], "characters": "\u290F" }, - "˝": { "codepoints": [733], "characters": "\u02DD" }, - "ď": { "codepoints": [271], "characters": "\u010F" }, - "д": { "codepoints": [1076], "characters": "\u0434" }, - "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, - "‡": { "codepoints": [8225], "characters": "\u2021" }, - "⇊": { "codepoints": [8650], "characters": "\u21CA" }, - "⩷": { "codepoints": [10871], "characters": "\u2A77" }, - "°": { "codepoints": [176], "characters": "\u00B0" }, - "°": { "codepoints": [176], "characters": "\u00B0" }, - "δ": { "codepoints": [948], "characters": "\u03B4" }, - "⦱": { "codepoints": [10673], "characters": "\u29B1" }, - "⥿": { "codepoints": [10623], "characters": "\u297F" }, - "𝔡": { "codepoints": [120097], "characters": "\uD835\uDD21" }, - "⇃": { "codepoints": [8643], "characters": "\u21C3" }, - "⇂": { "codepoints": [8642], "characters": "\u21C2" }, - "⋄": { "codepoints": [8900], "characters": "\u22C4" }, - "⋄": { "codepoints": [8900], "characters": "\u22C4" }, - "♦": { "codepoints": [9830], "characters": "\u2666" }, - "♦": { "codepoints": [9830], "characters": "\u2666" }, - "¨": { "codepoints": [168], "characters": "\u00A8" }, - "ϝ": { "codepoints": [989], "characters": "\u03DD" }, - "⋲": { "codepoints": [8946], "characters": "\u22F2" }, - "÷": { "codepoints": [247], "characters": "\u00F7" }, - "÷": { "codepoints": [247], "characters": "\u00F7" }, - "÷": { "codepoints": [247], "characters": "\u00F7" }, - "⋇": { "codepoints": [8903], "characters": "\u22C7" }, - "⋇": { "codepoints": [8903], "characters": "\u22C7" }, - "ђ": { "codepoints": [1106], "characters": "\u0452" }, - "⌞": { "codepoints": [8990], "characters": "\u231E" }, - "⌍": { "codepoints": [8973], "characters": "\u230D" }, - "$": { "codepoints": [36], "characters": "\u0024" }, - "𝕕": { "codepoints": [120149], "characters": "\uD835\uDD55" }, - "˙": { "codepoints": [729], "characters": "\u02D9" }, - "≐": { "codepoints": [8784], "characters": "\u2250" }, - "≑": { "codepoints": [8785], "characters": "\u2251" }, - "∸": { "codepoints": [8760], "characters": "\u2238" }, - "∔": { "codepoints": [8724], "characters": "\u2214" }, - "⊡": { "codepoints": [8865], "characters": "\u22A1" }, - "⌆": { "codepoints": [8966], "characters": "\u2306" }, - "↓": { "codepoints": [8595], "characters": "\u2193" }, - "⇊": { "codepoints": [8650], "characters": "\u21CA" }, - "⇃": { "codepoints": [8643], "characters": "\u21C3" }, - "⇂": { "codepoints": [8642], "characters": "\u21C2" }, - "⤐": { "codepoints": [10512], "characters": "\u2910" }, - "⌟": { "codepoints": [8991], "characters": "\u231F" }, - "⌌": { "codepoints": [8972], "characters": "\u230C" }, - "𝒹": { "codepoints": [119993], "characters": "\uD835\uDCB9" }, - "ѕ": { "codepoints": [1109], "characters": "\u0455" }, - "⧶": { "codepoints": [10742], "characters": "\u29F6" }, - "đ": { "codepoints": [273], "characters": "\u0111" }, - "⋱": { "codepoints": [8945], "characters": "\u22F1" }, - "▿": { "codepoints": [9663], "characters": "\u25BF" }, - "▾": { "codepoints": [9662], "characters": "\u25BE" }, - "⇵": { "codepoints": [8693], "characters": "\u21F5" }, - "⥯": { "codepoints": [10607], "characters": "\u296F" }, - "⦦": { "codepoints": [10662], "characters": "\u29A6" }, - "џ": { "codepoints": [1119], "characters": "\u045F" }, - "⟿": { "codepoints": [10239], "characters": "\u27FF" }, - "⩷": { "codepoints": [10871], "characters": "\u2A77" }, - "≑": { "codepoints": [8785], "characters": "\u2251" }, - "é": { "codepoints": [233], "characters": "\u00E9" }, - "é": { "codepoints": [233], "characters": "\u00E9" }, - "⩮": { "codepoints": [10862], "characters": "\u2A6E" }, - "ě": { "codepoints": [283], "characters": "\u011B" }, - "≖": { "codepoints": [8790], "characters": "\u2256" }, - "ê": { "codepoints": [234], "characters": "\u00EA" }, - "ê": { "codepoints": [234], "characters": "\u00EA" }, - "≕": { "codepoints": [8789], "characters": "\u2255" }, - "э": { "codepoints": [1101], "characters": "\u044D" }, - "ė": { "codepoints": [279], "characters": "\u0117" }, - "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, - "≒": { "codepoints": [8786], "characters": "\u2252" }, - "𝔢": { "codepoints": [120098], "characters": "\uD835\uDD22" }, - "⪚": { "codepoints": [10906], "characters": "\u2A9A" }, - "è": { "codepoints": [232], "characters": "\u00E8" }, - "è": { "codepoints": [232], "characters": "\u00E8" }, - "⪖": { "codepoints": [10902], "characters": "\u2A96" }, - "⪘": { "codepoints": [10904], "characters": "\u2A98" }, - "⪙": { "codepoints": [10905], "characters": "\u2A99" }, - "⏧": { "codepoints": [9191], "characters": "\u23E7" }, - "ℓ": { "codepoints": [8467], "characters": "\u2113" }, - "⪕": { "codepoints": [10901], "characters": "\u2A95" }, - "⪗": { "codepoints": [10903], "characters": "\u2A97" }, - "ē": { "codepoints": [275], "characters": "\u0113" }, - "∅": { "codepoints": [8709], "characters": "\u2205" }, - "∅": { "codepoints": [8709], "characters": "\u2205" }, - "∅": { "codepoints": [8709], "characters": "\u2205" }, - " ": { "codepoints": [8196], "characters": "\u2004" }, - " ": { "codepoints": [8197], "characters": "\u2005" }, - " ": { "codepoints": [8195], "characters": "\u2003" }, - "ŋ": { "codepoints": [331], "characters": "\u014B" }, - " ": { "codepoints": [8194], "characters": "\u2002" }, - "ę": { "codepoints": [281], "characters": "\u0119" }, - "𝕖": { "codepoints": [120150], "characters": "\uD835\uDD56" }, - "⋕": { "codepoints": [8917], "characters": "\u22D5" }, - "⧣": { "codepoints": [10723], "characters": "\u29E3" }, - "⩱": { "codepoints": [10865], "characters": "\u2A71" }, - "ε": { "codepoints": [949], "characters": "\u03B5" }, - "ε": { "codepoints": [949], "characters": "\u03B5" }, - "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, - "≖": { "codepoints": [8790], "characters": "\u2256" }, - "≕": { "codepoints": [8789], "characters": "\u2255" }, - "≂": { "codepoints": [8770], "characters": "\u2242" }, - "⪖": { "codepoints": [10902], "characters": "\u2A96" }, - "⪕": { "codepoints": [10901], "characters": "\u2A95" }, - "=": { "codepoints": [61], "characters": "\u003D" }, - "≟": { "codepoints": [8799], "characters": "\u225F" }, - "≡": { "codepoints": [8801], "characters": "\u2261" }, - "⩸": { "codepoints": [10872], "characters": "\u2A78" }, - "⧥": { "codepoints": [10725], "characters": "\u29E5" }, - "≓": { "codepoints": [8787], "characters": "\u2253" }, - "⥱": { "codepoints": [10609], "characters": "\u2971" }, - "ℯ": { "codepoints": [8495], "characters": "\u212F" }, - "≐": { "codepoints": [8784], "characters": "\u2250" }, - "≂": { "codepoints": [8770], "characters": "\u2242" }, - "η": { "codepoints": [951], "characters": "\u03B7" }, - "ð": { "codepoints": [240], "characters": "\u00F0" }, - "ð": { "codepoints": [240], "characters": "\u00F0" }, - "ë": { "codepoints": [235], "characters": "\u00EB" }, - "ë": { "codepoints": [235], "characters": "\u00EB" }, - "€": { "codepoints": [8364], "characters": "\u20AC" }, - "!": { "codepoints": [33], "characters": "\u0021" }, - "∃": { "codepoints": [8707], "characters": "\u2203" }, - "ℰ": { "codepoints": [8496], "characters": "\u2130" }, - "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, - "≒": { "codepoints": [8786], "characters": "\u2252" }, - "ф": { "codepoints": [1092], "characters": "\u0444" }, - "♀": { "codepoints": [9792], "characters": "\u2640" }, - "ffi": { "codepoints": [64259], "characters": "\uFB03" }, - "ff": { "codepoints": [64256], "characters": "\uFB00" }, - "ffl": { "codepoints": [64260], "characters": "\uFB04" }, - "𝔣": { "codepoints": [120099], "characters": "\uD835\uDD23" }, - "fi": { "codepoints": [64257], "characters": "\uFB01" }, - "fj": { "codepoints": [102, 106], "characters": "\u0066\u006A" }, - "♭": { "codepoints": [9837], "characters": "\u266D" }, - "fl": { "codepoints": [64258], "characters": "\uFB02" }, - "▱": { "codepoints": [9649], "characters": "\u25B1" }, - "ƒ": { "codepoints": [402], "characters": "\u0192" }, - "𝕗": { "codepoints": [120151], "characters": "\uD835\uDD57" }, - "∀": { "codepoints": [8704], "characters": "\u2200" }, - "⋔": { "codepoints": [8916], "characters": "\u22D4" }, - "⫙": { "codepoints": [10969], "characters": "\u2AD9" }, - "⨍": { "codepoints": [10765], "characters": "\u2A0D" }, - "½": { "codepoints": [189], "characters": "\u00BD" }, - "½": { "codepoints": [189], "characters": "\u00BD" }, - "⅓": { "codepoints": [8531], "characters": "\u2153" }, - "¼": { "codepoints": [188], "characters": "\u00BC" }, - "¼": { "codepoints": [188], "characters": "\u00BC" }, - "⅕": { "codepoints": [8533], "characters": "\u2155" }, - "⅙": { "codepoints": [8537], "characters": "\u2159" }, - "⅛": { "codepoints": [8539], "characters": "\u215B" }, - "⅔": { "codepoints": [8532], "characters": "\u2154" }, - "⅖": { "codepoints": [8534], "characters": "\u2156" }, - "¾": { "codepoints": [190], "characters": "\u00BE" }, - "¾": { "codepoints": [190], "characters": "\u00BE" }, - "⅗": { "codepoints": [8535], "characters": "\u2157" }, - "⅜": { "codepoints": [8540], "characters": "\u215C" }, - "⅘": { "codepoints": [8536], "characters": "\u2158" }, - "⅚": { "codepoints": [8538], "characters": "\u215A" }, - "⅝": { "codepoints": [8541], "characters": "\u215D" }, - "⅞": { "codepoints": [8542], "characters": "\u215E" }, - "⁄": { "codepoints": [8260], "characters": "\u2044" }, - "⌢": { "codepoints": [8994], "characters": "\u2322" }, - "𝒻": { "codepoints": [119995], "characters": "\uD835\uDCBB" }, - "≧": { "codepoints": [8807], "characters": "\u2267" }, - "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, - "ǵ": { "codepoints": [501], "characters": "\u01F5" }, - "γ": { "codepoints": [947], "characters": "\u03B3" }, - "ϝ": { "codepoints": [989], "characters": "\u03DD" }, - "⪆": { "codepoints": [10886], "characters": "\u2A86" }, - "ğ": { "codepoints": [287], "characters": "\u011F" }, - "ĝ": { "codepoints": [285], "characters": "\u011D" }, - "г": { "codepoints": [1075], "characters": "\u0433" }, - "ġ": { "codepoints": [289], "characters": "\u0121" }, - "≥": { "codepoints": [8805], "characters": "\u2265" }, - "⋛": { "codepoints": [8923], "characters": "\u22DB" }, - "≥": { "codepoints": [8805], "characters": "\u2265" }, - "≧": { "codepoints": [8807], "characters": "\u2267" }, - "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, - "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, - "⪩": { "codepoints": [10921], "characters": "\u2AA9" }, - "⪀": { "codepoints": [10880], "characters": "\u2A80" }, - "⪂": { "codepoints": [10882], "characters": "\u2A82" }, - "⪄": { "codepoints": [10884], "characters": "\u2A84" }, - "⋛︀": { "codepoints": [8923, 65024], "characters": "\u22DB\uFE00" }, - "⪔": { "codepoints": [10900], "characters": "\u2A94" }, - "𝔤": { "codepoints": [120100], "characters": "\uD835\uDD24" }, - "≫": { "codepoints": [8811], "characters": "\u226B" }, - "⋙": { "codepoints": [8921], "characters": "\u22D9" }, - "ℷ": { "codepoints": [8503], "characters": "\u2137" }, - "ѓ": { "codepoints": [1107], "characters": "\u0453" }, - "≷": { "codepoints": [8823], "characters": "\u2277" }, - "⪒": { "codepoints": [10898], "characters": "\u2A92" }, - "⪥": { "codepoints": [10917], "characters": "\u2AA5" }, - "⪤": { "codepoints": [10916], "characters": "\u2AA4" }, - "≩": { "codepoints": [8809], "characters": "\u2269" }, - "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, - "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, - "⪈": { "codepoints": [10888], "characters": "\u2A88" }, - "⪈": { "codepoints": [10888], "characters": "\u2A88" }, - "≩": { "codepoints": [8809], "characters": "\u2269" }, - "⋧": { "codepoints": [8935], "characters": "\u22E7" }, - "𝕘": { "codepoints": [120152], "characters": "\uD835\uDD58" }, - "`": { "codepoints": [96], "characters": "\u0060" }, - "ℊ": { "codepoints": [8458], "characters": "\u210A" }, - "≳": { "codepoints": [8819], "characters": "\u2273" }, - "⪎": { "codepoints": [10894], "characters": "\u2A8E" }, - "⪐": { "codepoints": [10896], "characters": "\u2A90" }, - ">": { "codepoints": [62], "characters": "\u003E" }, - ">": { "codepoints": [62], "characters": "\u003E" }, - "⪧": { "codepoints": [10919], "characters": "\u2AA7" }, - "⩺": { "codepoints": [10874], "characters": "\u2A7A" }, - "⋗": { "codepoints": [8919], "characters": "\u22D7" }, - "⦕": { "codepoints": [10645], "characters": "\u2995" }, - "⩼": { "codepoints": [10876], "characters": "\u2A7C" }, - "⪆": { "codepoints": [10886], "characters": "\u2A86" }, - "⥸": { "codepoints": [10616], "characters": "\u2978" }, - "⋗": { "codepoints": [8919], "characters": "\u22D7" }, - "⋛": { "codepoints": [8923], "characters": "\u22DB" }, - "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, - "≷": { "codepoints": [8823], "characters": "\u2277" }, - "≳": { "codepoints": [8819], "characters": "\u2273" }, - "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, - "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, - " ": { "codepoints": [8202], "characters": "\u200A" }, - "½": { "codepoints": [189], "characters": "\u00BD" }, - "ℋ": { "codepoints": [8459], "characters": "\u210B" }, - "ъ": { "codepoints": [1098], "characters": "\u044A" }, - "↔": { "codepoints": [8596], "characters": "\u2194" }, - "⥈": { "codepoints": [10568], "characters": "\u2948" }, - "↭": { "codepoints": [8621], "characters": "\u21AD" }, - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, - "ĥ": { "codepoints": [293], "characters": "\u0125" }, - "♥": { "codepoints": [9829], "characters": "\u2665" }, - "♥": { "codepoints": [9829], "characters": "\u2665" }, - "…": { "codepoints": [8230], "characters": "\u2026" }, - "⊹": { "codepoints": [8889], "characters": "\u22B9" }, - "𝔥": { "codepoints": [120101], "characters": "\uD835\uDD25" }, - "⤥": { "codepoints": [10533], "characters": "\u2925" }, - "⤦": { "codepoints": [10534], "characters": "\u2926" }, - "⇿": { "codepoints": [8703], "characters": "\u21FF" }, - "∻": { "codepoints": [8763], "characters": "\u223B" }, - "↩": { "codepoints": [8617], "characters": "\u21A9" }, - "↪": { "codepoints": [8618], "characters": "\u21AA" }, - "𝕙": { "codepoints": [120153], "characters": "\uD835\uDD59" }, - "―": { "codepoints": [8213], "characters": "\u2015" }, - "𝒽": { "codepoints": [119997], "characters": "\uD835\uDCBD" }, - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, - "ħ": { "codepoints": [295], "characters": "\u0127" }, - "⁃": { "codepoints": [8259], "characters": "\u2043" }, - "‐": { "codepoints": [8208], "characters": "\u2010" }, - "í": { "codepoints": [237], "characters": "\u00ED" }, - "í": { "codepoints": [237], "characters": "\u00ED" }, - "⁣": { "codepoints": [8291], "characters": "\u2063" }, - "î": { "codepoints": [238], "characters": "\u00EE" }, - "î": { "codepoints": [238], "characters": "\u00EE" }, - "и": { "codepoints": [1080], "characters": "\u0438" }, - "е": { "codepoints": [1077], "characters": "\u0435" }, - "¡": { "codepoints": [161], "characters": "\u00A1" }, - "¡": { "codepoints": [161], "characters": "\u00A1" }, - "⇔": { "codepoints": [8660], "characters": "\u21D4" }, - "𝔦": { "codepoints": [120102], "characters": "\uD835\uDD26" }, - "ì": { "codepoints": [236], "characters": "\u00EC" }, - "ì": { "codepoints": [236], "characters": "\u00EC" }, - "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, - "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, - "∭": { "codepoints": [8749], "characters": "\u222D" }, - "⧜": { "codepoints": [10716], "characters": "\u29DC" }, - "℩": { "codepoints": [8489], "characters": "\u2129" }, - "ij": { "codepoints": [307], "characters": "\u0133" }, - "ī": { "codepoints": [299], "characters": "\u012B" }, - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, - "ℐ": { "codepoints": [8464], "characters": "\u2110" }, - "ℑ": { "codepoints": [8465], "characters": "\u2111" }, - "ı": { "codepoints": [305], "characters": "\u0131" }, - "⊷": { "codepoints": [8887], "characters": "\u22B7" }, - "Ƶ": { "codepoints": [437], "characters": "\u01B5" }, - "∈": { "codepoints": [8712], "characters": "\u2208" }, - "℅": { "codepoints": [8453], "characters": "\u2105" }, - "∞": { "codepoints": [8734], "characters": "\u221E" }, - "⧝": { "codepoints": [10717], "characters": "\u29DD" }, - "ı": { "codepoints": [305], "characters": "\u0131" }, - "∫": { "codepoints": [8747], "characters": "\u222B" }, - "⊺": { "codepoints": [8890], "characters": "\u22BA" }, - "ℤ": { "codepoints": [8484], "characters": "\u2124" }, - "⊺": { "codepoints": [8890], "characters": "\u22BA" }, - "⨗": { "codepoints": [10775], "characters": "\u2A17" }, - "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, - "ё": { "codepoints": [1105], "characters": "\u0451" }, - "į": { "codepoints": [303], "characters": "\u012F" }, - "𝕚": { "codepoints": [120154], "characters": "\uD835\uDD5A" }, - "ι": { "codepoints": [953], "characters": "\u03B9" }, - "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, - "¿": { "codepoints": [191], "characters": "\u00BF" }, - "¿": { "codepoints": [191], "characters": "\u00BF" }, - "𝒾": { "codepoints": [119998], "characters": "\uD835\uDCBE" }, - "∈": { "codepoints": [8712], "characters": "\u2208" }, - "⋹": { "codepoints": [8953], "characters": "\u22F9" }, - "⋵": { "codepoints": [8949], "characters": "\u22F5" }, - "⋴": { "codepoints": [8948], "characters": "\u22F4" }, - "⋳": { "codepoints": [8947], "characters": "\u22F3" }, - "∈": { "codepoints": [8712], "characters": "\u2208" }, - "⁢": { "codepoints": [8290], "characters": "\u2062" }, - "ĩ": { "codepoints": [297], "characters": "\u0129" }, - "і": { "codepoints": [1110], "characters": "\u0456" }, - "ï": { "codepoints": [239], "characters": "\u00EF" }, - "ï": { "codepoints": [239], "characters": "\u00EF" }, - "ĵ": { "codepoints": [309], "characters": "\u0135" }, - "й": { "codepoints": [1081], "characters": "\u0439" }, - "𝔧": { "codepoints": [120103], "characters": "\uD835\uDD27" }, - "ȷ": { "codepoints": [567], "characters": "\u0237" }, - "𝕛": { "codepoints": [120155], "characters": "\uD835\uDD5B" }, - "𝒿": { "codepoints": [119999], "characters": "\uD835\uDCBF" }, - "ј": { "codepoints": [1112], "characters": "\u0458" }, - "є": { "codepoints": [1108], "characters": "\u0454" }, - "κ": { "codepoints": [954], "characters": "\u03BA" }, - "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, - "ķ": { "codepoints": [311], "characters": "\u0137" }, - "к": { "codepoints": [1082], "characters": "\u043A" }, - "𝔨": { "codepoints": [120104], "characters": "\uD835\uDD28" }, - "ĸ": { "codepoints": [312], "characters": "\u0138" }, - "х": { "codepoints": [1093], "characters": "\u0445" }, - "ќ": { "codepoints": [1116], "characters": "\u045C" }, - "𝕜": { "codepoints": [120156], "characters": "\uD835\uDD5C" }, - "𝓀": { "codepoints": [120000], "characters": "\uD835\uDCC0" }, - "⇚": { "codepoints": [8666], "characters": "\u21DA" }, - "⇐": { "codepoints": [8656], "characters": "\u21D0" }, - "⤛": { "codepoints": [10523], "characters": "\u291B" }, - "⤎": { "codepoints": [10510], "characters": "\u290E" }, - "≦": { "codepoints": [8806], "characters": "\u2266" }, - "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, - "⥢": { "codepoints": [10594], "characters": "\u2962" }, - "ĺ": { "codepoints": [314], "characters": "\u013A" }, - "⦴": { "codepoints": [10676], "characters": "\u29B4" }, - "ℒ": { "codepoints": [8466], "characters": "\u2112" }, - "λ": { "codepoints": [955], "characters": "\u03BB" }, - "⟨": { "codepoints": [10216], "characters": "\u27E8" }, - "⦑": { "codepoints": [10641], "characters": "\u2991" }, - "⟨": { "codepoints": [10216], "characters": "\u27E8" }, - "⪅": { "codepoints": [10885], "characters": "\u2A85" }, - "«": { "codepoints": [171], "characters": "\u00AB" }, - "«": { "codepoints": [171], "characters": "\u00AB" }, - "←": { "codepoints": [8592], "characters": "\u2190" }, - "⇤": { "codepoints": [8676], "characters": "\u21E4" }, - "⤟": { "codepoints": [10527], "characters": "\u291F" }, - "⤝": { "codepoints": [10525], "characters": "\u291D" }, - "↩": { "codepoints": [8617], "characters": "\u21A9" }, - "↫": { "codepoints": [8619], "characters": "\u21AB" }, - "⤹": { "codepoints": [10553], "characters": "\u2939" }, - "⥳": { "codepoints": [10611], "characters": "\u2973" }, - "↢": { "codepoints": [8610], "characters": "\u21A2" }, - "⪫": { "codepoints": [10923], "characters": "\u2AAB" }, - "⤙": { "codepoints": [10521], "characters": "\u2919" }, - "⪭": { "codepoints": [10925], "characters": "\u2AAD" }, - "⪭︀": { "codepoints": [10925, 65024], "characters": "\u2AAD\uFE00" }, - "⤌": { "codepoints": [10508], "characters": "\u290C" }, - "❲": { "codepoints": [10098], "characters": "\u2772" }, - "{": { "codepoints": [123], "characters": "\u007B" }, - "[": { "codepoints": [91], "characters": "\u005B" }, - "⦋": { "codepoints": [10635], "characters": "\u298B" }, - "⦏": { "codepoints": [10639], "characters": "\u298F" }, - "⦍": { "codepoints": [10637], "characters": "\u298D" }, - "ľ": { "codepoints": [318], "characters": "\u013E" }, - "ļ": { "codepoints": [316], "characters": "\u013C" }, - "⌈": { "codepoints": [8968], "characters": "\u2308" }, - "{": { "codepoints": [123], "characters": "\u007B" }, - "л": { "codepoints": [1083], "characters": "\u043B" }, - "⤶": { "codepoints": [10550], "characters": "\u2936" }, - "“": { "codepoints": [8220], "characters": "\u201C" }, - "„": { "codepoints": [8222], "characters": "\u201E" }, - "⥧": { "codepoints": [10599], "characters": "\u2967" }, - "⥋": { "codepoints": [10571], "characters": "\u294B" }, - "↲": { "codepoints": [8626], "characters": "\u21B2" }, - "≤": { "codepoints": [8804], "characters": "\u2264" }, - "←": { "codepoints": [8592], "characters": "\u2190" }, - "↢": { "codepoints": [8610], "characters": "\u21A2" }, - "↽": { "codepoints": [8637], "characters": "\u21BD" }, - "↼": { "codepoints": [8636], "characters": "\u21BC" }, - "⇇": { "codepoints": [8647], "characters": "\u21C7" }, - "↔": { "codepoints": [8596], "characters": "\u2194" }, - "⇆": { "codepoints": [8646], "characters": "\u21C6" }, - "⇋": { "codepoints": [8651], "characters": "\u21CB" }, - "↭": { "codepoints": [8621], "characters": "\u21AD" }, - "⋋": { "codepoints": [8907], "characters": "\u22CB" }, - "⋚": { "codepoints": [8922], "characters": "\u22DA" }, - "≤": { "codepoints": [8804], "characters": "\u2264" }, - "≦": { "codepoints": [8806], "characters": "\u2266" }, - "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, - "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, - "⪨": { "codepoints": [10920], "characters": "\u2AA8" }, - "⩿": { "codepoints": [10879], "characters": "\u2A7F" }, - "⪁": { "codepoints": [10881], "characters": "\u2A81" }, - "⪃": { "codepoints": [10883], "characters": "\u2A83" }, - "⋚︀": { "codepoints": [8922, 65024], "characters": "\u22DA\uFE00" }, - "⪓": { "codepoints": [10899], "characters": "\u2A93" }, - "⪅": { "codepoints": [10885], "characters": "\u2A85" }, - "⋖": { "codepoints": [8918], "characters": "\u22D6" }, - "⋚": { "codepoints": [8922], "characters": "\u22DA" }, - "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, - "≶": { "codepoints": [8822], "characters": "\u2276" }, - "≲": { "codepoints": [8818], "characters": "\u2272" }, - "⥼": { "codepoints": [10620], "characters": "\u297C" }, - "⌊": { "codepoints": [8970], "characters": "\u230A" }, - "𝔩": { "codepoints": [120105], "characters": "\uD835\uDD29" }, - "≶": { "codepoints": [8822], "characters": "\u2276" }, - "⪑": { "codepoints": [10897], "characters": "\u2A91" }, - "↽": { "codepoints": [8637], "characters": "\u21BD" }, - "↼": { "codepoints": [8636], "characters": "\u21BC" }, - "⥪": { "codepoints": [10602], "characters": "\u296A" }, - "▄": { "codepoints": [9604], "characters": "\u2584" }, - "љ": { "codepoints": [1113], "characters": "\u0459" }, - "≪": { "codepoints": [8810], "characters": "\u226A" }, - "⇇": { "codepoints": [8647], "characters": "\u21C7" }, - "⌞": { "codepoints": [8990], "characters": "\u231E" }, - "⥫": { "codepoints": [10603], "characters": "\u296B" }, - "◺": { "codepoints": [9722], "characters": "\u25FA" }, - "ŀ": { "codepoints": [320], "characters": "\u0140" }, - "⎰": { "codepoints": [9136], "characters": "\u23B0" }, - "⎰": { "codepoints": [9136], "characters": "\u23B0" }, - "≨": { "codepoints": [8808], "characters": "\u2268" }, - "⪉": { "codepoints": [10889], "characters": "\u2A89" }, - "⪉": { "codepoints": [10889], "characters": "\u2A89" }, - "⪇": { "codepoints": [10887], "characters": "\u2A87" }, - "⪇": { "codepoints": [10887], "characters": "\u2A87" }, - "≨": { "codepoints": [8808], "characters": "\u2268" }, - "⋦": { "codepoints": [8934], "characters": "\u22E6" }, - "⟬": { "codepoints": [10220], "characters": "\u27EC" }, - "⇽": { "codepoints": [8701], "characters": "\u21FD" }, - "⟦": { "codepoints": [10214], "characters": "\u27E6" }, - "⟵": { "codepoints": [10229], "characters": "\u27F5" }, - "⟷": { "codepoints": [10231], "characters": "\u27F7" }, - "⟼": { "codepoints": [10236], "characters": "\u27FC" }, - "⟶": { "codepoints": [10230], "characters": "\u27F6" }, - "↫": { "codepoints": [8619], "characters": "\u21AB" }, - "↬": { "codepoints": [8620], "characters": "\u21AC" }, - "⦅": { "codepoints": [10629], "characters": "\u2985" }, - "𝕝": { "codepoints": [120157], "characters": "\uD835\uDD5D" }, - "⨭": { "codepoints": [10797], "characters": "\u2A2D" }, - "⨴": { "codepoints": [10804], "characters": "\u2A34" }, - "∗": { "codepoints": [8727], "characters": "\u2217" }, - "_": { "codepoints": [95], "characters": "\u005F" }, - "◊": { "codepoints": [9674], "characters": "\u25CA" }, - "◊": { "codepoints": [9674], "characters": "\u25CA" }, - "⧫": { "codepoints": [10731], "characters": "\u29EB" }, - "(": { "codepoints": [40], "characters": "\u0028" }, - "⦓": { "codepoints": [10643], "characters": "\u2993" }, - "⇆": { "codepoints": [8646], "characters": "\u21C6" }, - "⌟": { "codepoints": [8991], "characters": "\u231F" }, - "⇋": { "codepoints": [8651], "characters": "\u21CB" }, - "⥭": { "codepoints": [10605], "characters": "\u296D" }, - "‎": { "codepoints": [8206], "characters": "\u200E" }, - "⊿": { "codepoints": [8895], "characters": "\u22BF" }, - "‹": { "codepoints": [8249], "characters": "\u2039" }, - "𝓁": { "codepoints": [120001], "characters": "\uD835\uDCC1" }, - "↰": { "codepoints": [8624], "characters": "\u21B0" }, - "≲": { "codepoints": [8818], "characters": "\u2272" }, - "⪍": { "codepoints": [10893], "characters": "\u2A8D" }, - "⪏": { "codepoints": [10895], "characters": "\u2A8F" }, - "[": { "codepoints": [91], "characters": "\u005B" }, - "‘": { "codepoints": [8216], "characters": "\u2018" }, - "‚": { "codepoints": [8218], "characters": "\u201A" }, - "ł": { "codepoints": [322], "characters": "\u0142" }, - "<": { "codepoints": [60], "characters": "\u003C" }, - "<": { "codepoints": [60], "characters": "\u003C" }, - "⪦": { "codepoints": [10918], "characters": "\u2AA6" }, - "⩹": { "codepoints": [10873], "characters": "\u2A79" }, - "⋖": { "codepoints": [8918], "characters": "\u22D6" }, - "⋋": { "codepoints": [8907], "characters": "\u22CB" }, - "⋉": { "codepoints": [8905], "characters": "\u22C9" }, - "⥶": { "codepoints": [10614], "characters": "\u2976" }, - "⩻": { "codepoints": [10875], "characters": "\u2A7B" }, - "⦖": { "codepoints": [10646], "characters": "\u2996" }, - "◃": { "codepoints": [9667], "characters": "\u25C3" }, - "⊴": { "codepoints": [8884], "characters": "\u22B4" }, - "◂": { "codepoints": [9666], "characters": "\u25C2" }, - "⥊": { "codepoints": [10570], "characters": "\u294A" }, - "⥦": { "codepoints": [10598], "characters": "\u2966" }, - "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, - "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, - "∺": { "codepoints": [8762], "characters": "\u223A" }, - "¯": { "codepoints": [175], "characters": "\u00AF" }, - "¯": { "codepoints": [175], "characters": "\u00AF" }, - "♂": { "codepoints": [9794], "characters": "\u2642" }, - "✠": { "codepoints": [10016], "characters": "\u2720" }, - "✠": { "codepoints": [10016], "characters": "\u2720" }, - "↦": { "codepoints": [8614], "characters": "\u21A6" }, - "↦": { "codepoints": [8614], "characters": "\u21A6" }, - "↧": { "codepoints": [8615], "characters": "\u21A7" }, - "↤": { "codepoints": [8612], "characters": "\u21A4" }, - "↥": { "codepoints": [8613], "characters": "\u21A5" }, - "▮": { "codepoints": [9646], "characters": "\u25AE" }, - "⨩": { "codepoints": [10793], "characters": "\u2A29" }, - "м": { "codepoints": [1084], "characters": "\u043C" }, - "—": { "codepoints": [8212], "characters": "\u2014" }, - "∡": { "codepoints": [8737], "characters": "\u2221" }, - "𝔪": { "codepoints": [120106], "characters": "\uD835\uDD2A" }, - "℧": { "codepoints": [8487], "characters": "\u2127" }, - "µ": { "codepoints": [181], "characters": "\u00B5" }, - "µ": { "codepoints": [181], "characters": "\u00B5" }, - "∣": { "codepoints": [8739], "characters": "\u2223" }, - "*": { "codepoints": [42], "characters": "\u002A" }, - "⫰": { "codepoints": [10992], "characters": "\u2AF0" }, - "·": { "codepoints": [183], "characters": "\u00B7" }, - "·": { "codepoints": [183], "characters": "\u00B7" }, - "−": { "codepoints": [8722], "characters": "\u2212" }, - "⊟": { "codepoints": [8863], "characters": "\u229F" }, - "∸": { "codepoints": [8760], "characters": "\u2238" }, - "⨪": { "codepoints": [10794], "characters": "\u2A2A" }, - "⫛": { "codepoints": [10971], "characters": "\u2ADB" }, - "…": { "codepoints": [8230], "characters": "\u2026" }, - "∓": { "codepoints": [8723], "characters": "\u2213" }, - "⊧": { "codepoints": [8871], "characters": "\u22A7" }, - "𝕞": { "codepoints": [120158], "characters": "\uD835\uDD5E" }, - "∓": { "codepoints": [8723], "characters": "\u2213" }, - "𝓂": { "codepoints": [120002], "characters": "\uD835\uDCC2" }, - "∾": { "codepoints": [8766], "characters": "\u223E" }, - "μ": { "codepoints": [956], "characters": "\u03BC" }, - "⊸": { "codepoints": [8888], "characters": "\u22B8" }, - "⊸": { "codepoints": [8888], "characters": "\u22B8" }, - "⋙̸": { "codepoints": [8921, 824], "characters": "\u22D9\u0338" }, - "≫⃒": { "codepoints": [8811, 8402], "characters": "\u226B\u20D2" }, - "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, - "⇍": { "codepoints": [8653], "characters": "\u21CD" }, - "⇎": { "codepoints": [8654], "characters": "\u21CE" }, - "⋘̸": { "codepoints": [8920, 824], "characters": "\u22D8\u0338" }, - "≪⃒": { "codepoints": [8810, 8402], "characters": "\u226A\u20D2" }, - "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, - "⇏": { "codepoints": [8655], "characters": "\u21CF" }, - "⊯": { "codepoints": [8879], "characters": "\u22AF" }, - "⊮": { "codepoints": [8878], "characters": "\u22AE" }, - "∇": { "codepoints": [8711], "characters": "\u2207" }, - "ń": { "codepoints": [324], "characters": "\u0144" }, - "∠⃒": { "codepoints": [8736, 8402], "characters": "\u2220\u20D2" }, - "≉": { "codepoints": [8777], "characters": "\u2249" }, - "⩰̸": { "codepoints": [10864, 824], "characters": "\u2A70\u0338" }, - "≋̸": { "codepoints": [8779, 824], "characters": "\u224B\u0338" }, - "ʼn": { "codepoints": [329], "characters": "\u0149" }, - "≉": { "codepoints": [8777], "characters": "\u2249" }, - "♮": { "codepoints": [9838], "characters": "\u266E" }, - "♮": { "codepoints": [9838], "characters": "\u266E" }, - "ℕ": { "codepoints": [8469], "characters": "\u2115" }, - " ": { "codepoints": [160], "characters": "\u00A0" }, - " ": { "codepoints": [160], "characters": "\u00A0" }, - "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, - "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, - "⩃": { "codepoints": [10819], "characters": "\u2A43" }, - "ň": { "codepoints": [328], "characters": "\u0148" }, - "ņ": { "codepoints": [326], "characters": "\u0146" }, - "≇": { "codepoints": [8775], "characters": "\u2247" }, - "⩭̸": { "codepoints": [10861, 824], "characters": "\u2A6D\u0338" }, - "⩂": { "codepoints": [10818], "characters": "\u2A42" }, - "н": { "codepoints": [1085], "characters": "\u043D" }, - "–": { "codepoints": [8211], "characters": "\u2013" }, - "≠": { "codepoints": [8800], "characters": "\u2260" }, - "⇗": { "codepoints": [8663], "characters": "\u21D7" }, - "⤤": { "codepoints": [10532], "characters": "\u2924" }, - "↗": { "codepoints": [8599], "characters": "\u2197" }, - "↗": { "codepoints": [8599], "characters": "\u2197" }, - "≐̸": { "codepoints": [8784, 824], "characters": "\u2250\u0338" }, - "≢": { "codepoints": [8802], "characters": "\u2262" }, - "⤨": { "codepoints": [10536], "characters": "\u2928" }, - "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, - "∄": { "codepoints": [8708], "characters": "\u2204" }, - "∄": { "codepoints": [8708], "characters": "\u2204" }, - "𝔫": { "codepoints": [120107], "characters": "\uD835\uDD2B" }, - "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, - "≱": { "codepoints": [8817], "characters": "\u2271" }, - "≱": { "codepoints": [8817], "characters": "\u2271" }, - "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, - "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, - "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, - "≵": { "codepoints": [8821], "characters": "\u2275" }, - "≯": { "codepoints": [8815], "characters": "\u226F" }, - "≯": { "codepoints": [8815], "characters": "\u226F" }, - "⇎": { "codepoints": [8654], "characters": "\u21CE" }, - "↮": { "codepoints": [8622], "characters": "\u21AE" }, - "⫲": { "codepoints": [10994], "characters": "\u2AF2" }, - "∋": { "codepoints": [8715], "characters": "\u220B" }, - "⋼": { "codepoints": [8956], "characters": "\u22FC" }, - "⋺": { "codepoints": [8954], "characters": "\u22FA" }, - "∋": { "codepoints": [8715], "characters": "\u220B" }, - "њ": { "codepoints": [1114], "characters": "\u045A" }, - "⇍": { "codepoints": [8653], "characters": "\u21CD" }, - "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, - "↚": { "codepoints": [8602], "characters": "\u219A" }, - "‥": { "codepoints": [8229], "characters": "\u2025" }, - "≰": { "codepoints": [8816], "characters": "\u2270" }, - "↚": { "codepoints": [8602], "characters": "\u219A" }, - "↮": { "codepoints": [8622], "characters": "\u21AE" }, - "≰": { "codepoints": [8816], "characters": "\u2270" }, - "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, - "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, - "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, - "≮": { "codepoints": [8814], "characters": "\u226E" }, - "≴": { "codepoints": [8820], "characters": "\u2274" }, - "≮": { "codepoints": [8814], "characters": "\u226E" }, - "⋪": { "codepoints": [8938], "characters": "\u22EA" }, - "⋬": { "codepoints": [8940], "characters": "\u22EC" }, - "∤": { "codepoints": [8740], "characters": "\u2224" }, - "𝕟": { "codepoints": [120159], "characters": "\uD835\uDD5F" }, - "¬": { "codepoints": [172], "characters": "\u00AC" }, - "¬": { "codepoints": [172], "characters": "\u00AC" }, - "∉": { "codepoints": [8713], "characters": "\u2209" }, - "⋹̸": { "codepoints": [8953, 824], "characters": "\u22F9\u0338" }, - "⋵̸": { "codepoints": [8949, 824], "characters": "\u22F5\u0338" }, - "∉": { "codepoints": [8713], "characters": "\u2209" }, - "⋷": { "codepoints": [8951], "characters": "\u22F7" }, - "⋶": { "codepoints": [8950], "characters": "\u22F6" }, - "∌": { "codepoints": [8716], "characters": "\u220C" }, - "∌": { "codepoints": [8716], "characters": "\u220C" }, - "⋾": { "codepoints": [8958], "characters": "\u22FE" }, - "⋽": { "codepoints": [8957], "characters": "\u22FD" }, - "∦": { "codepoints": [8742], "characters": "\u2226" }, - "∦": { "codepoints": [8742], "characters": "\u2226" }, - "⫽⃥": { "codepoints": [11005, 8421], "characters": "\u2AFD\u20E5" }, - "∂̸": { "codepoints": [8706, 824], "characters": "\u2202\u0338" }, - "⨔": { "codepoints": [10772], "characters": "\u2A14" }, - "⊀": { "codepoints": [8832], "characters": "\u2280" }, - "⋠": { "codepoints": [8928], "characters": "\u22E0" }, - "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, - "⊀": { "codepoints": [8832], "characters": "\u2280" }, - "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, - "⇏": { "codepoints": [8655], "characters": "\u21CF" }, - "↛": { "codepoints": [8603], "characters": "\u219B" }, - "⤳̸": { "codepoints": [10547, 824], "characters": "\u2933\u0338" }, - "↝̸": { "codepoints": [8605, 824], "characters": "\u219D\u0338" }, - "↛": { "codepoints": [8603], "characters": "\u219B" }, - "⋫": { "codepoints": [8939], "characters": "\u22EB" }, - "⋭": { "codepoints": [8941], "characters": "\u22ED" }, - "⊁": { "codepoints": [8833], "characters": "\u2281" }, - "⋡": { "codepoints": [8929], "characters": "\u22E1" }, - "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, - "𝓃": { "codepoints": [120003], "characters": "\uD835\uDCC3" }, - "∤": { "codepoints": [8740], "characters": "\u2224" }, - "∦": { "codepoints": [8742], "characters": "\u2226" }, - "≁": { "codepoints": [8769], "characters": "\u2241" }, - "≄": { "codepoints": [8772], "characters": "\u2244" }, - "≄": { "codepoints": [8772], "characters": "\u2244" }, - "∤": { "codepoints": [8740], "characters": "\u2224" }, - "∦": { "codepoints": [8742], "characters": "\u2226" }, - "⋢": { "codepoints": [8930], "characters": "\u22E2" }, - "⋣": { "codepoints": [8931], "characters": "\u22E3" }, - "⊄": { "codepoints": [8836], "characters": "\u2284" }, - "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, - "⊈": { "codepoints": [8840], "characters": "\u2288" }, - "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, - "⊈": { "codepoints": [8840], "characters": "\u2288" }, - "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, - "⊁": { "codepoints": [8833], "characters": "\u2281" }, - "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, - "⊅": { "codepoints": [8837], "characters": "\u2285" }, - "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, - "⊉": { "codepoints": [8841], "characters": "\u2289" }, - "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, - "⊉": { "codepoints": [8841], "characters": "\u2289" }, - "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, - "≹": { "codepoints": [8825], "characters": "\u2279" }, - "ñ": { "codepoints": [241], "characters": "\u00F1" }, - "ñ": { "codepoints": [241], "characters": "\u00F1" }, - "≸": { "codepoints": [8824], "characters": "\u2278" }, - "⋪": { "codepoints": [8938], "characters": "\u22EA" }, - "⋬": { "codepoints": [8940], "characters": "\u22EC" }, - "⋫": { "codepoints": [8939], "characters": "\u22EB" }, - "⋭": { "codepoints": [8941], "characters": "\u22ED" }, - "ν": { "codepoints": [957], "characters": "\u03BD" }, - "#": { "codepoints": [35], "characters": "\u0023" }, - "№": { "codepoints": [8470], "characters": "\u2116" }, - " ": { "codepoints": [8199], "characters": "\u2007" }, - "⊭": { "codepoints": [8877], "characters": "\u22AD" }, - "⤄": { "codepoints": [10500], "characters": "\u2904" }, - "≍⃒": { "codepoints": [8781, 8402], "characters": "\u224D\u20D2" }, - "⊬": { "codepoints": [8876], "characters": "\u22AC" }, - "≥⃒": { "codepoints": [8805, 8402], "characters": "\u2265\u20D2" }, - ">⃒": { "codepoints": [62, 8402], "characters": "\u003E\u20D2" }, - "⧞": { "codepoints": [10718], "characters": "\u29DE" }, - "⤂": { "codepoints": [10498], "characters": "\u2902" }, - "≤⃒": { "codepoints": [8804, 8402], "characters": "\u2264\u20D2" }, - "<⃒": { "codepoints": [60, 8402], "characters": "\u003C\u20D2" }, - "⊴⃒": { "codepoints": [8884, 8402], "characters": "\u22B4\u20D2" }, - "⤃": { "codepoints": [10499], "characters": "\u2903" }, - "⊵⃒": { "codepoints": [8885, 8402], "characters": "\u22B5\u20D2" }, - "∼⃒": { "codepoints": [8764, 8402], "characters": "\u223C\u20D2" }, - "⇖": { "codepoints": [8662], "characters": "\u21D6" }, - "⤣": { "codepoints": [10531], "characters": "\u2923" }, - "↖": { "codepoints": [8598], "characters": "\u2196" }, - "↖": { "codepoints": [8598], "characters": "\u2196" }, - "⤧": { "codepoints": [10535], "characters": "\u2927" }, - "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, - "ó": { "codepoints": [243], "characters": "\u00F3" }, - "ó": { "codepoints": [243], "characters": "\u00F3" }, - "⊛": { "codepoints": [8859], "characters": "\u229B" }, - "⊚": { "codepoints": [8858], "characters": "\u229A" }, - "ô": { "codepoints": [244], "characters": "\u00F4" }, - "ô": { "codepoints": [244], "characters": "\u00F4" }, - "о": { "codepoints": [1086], "characters": "\u043E" }, - "⊝": { "codepoints": [8861], "characters": "\u229D" }, - "ő": { "codepoints": [337], "characters": "\u0151" }, - "⨸": { "codepoints": [10808], "characters": "\u2A38" }, - "⊙": { "codepoints": [8857], "characters": "\u2299" }, - "⦼": { "codepoints": [10684], "characters": "\u29BC" }, - "œ": { "codepoints": [339], "characters": "\u0153" }, - "⦿": { "codepoints": [10687], "characters": "\u29BF" }, - "𝔬": { "codepoints": [120108], "characters": "\uD835\uDD2C" }, - "˛": { "codepoints": [731], "characters": "\u02DB" }, - "ò": { "codepoints": [242], "characters": "\u00F2" }, - "ò": { "codepoints": [242], "characters": "\u00F2" }, - "⧁": { "codepoints": [10689], "characters": "\u29C1" }, - "⦵": { "codepoints": [10677], "characters": "\u29B5" }, - "Ω": { "codepoints": [937], "characters": "\u03A9" }, - "∮": { "codepoints": [8750], "characters": "\u222E" }, - "↺": { "codepoints": [8634], "characters": "\u21BA" }, - "⦾": { "codepoints": [10686], "characters": "\u29BE" }, - "⦻": { "codepoints": [10683], "characters": "\u29BB" }, - "‾": { "codepoints": [8254], "characters": "\u203E" }, - "⧀": { "codepoints": [10688], "characters": "\u29C0" }, - "ō": { "codepoints": [333], "characters": "\u014D" }, - "ω": { "codepoints": [969], "characters": "\u03C9" }, - "ο": { "codepoints": [959], "characters": "\u03BF" }, - "⦶": { "codepoints": [10678], "characters": "\u29B6" }, - "⊖": { "codepoints": [8854], "characters": "\u2296" }, - "𝕠": { "codepoints": [120160], "characters": "\uD835\uDD60" }, - "⦷": { "codepoints": [10679], "characters": "\u29B7" }, - "⦹": { "codepoints": [10681], "characters": "\u29B9" }, - "⊕": { "codepoints": [8853], "characters": "\u2295" }, - "∨": { "codepoints": [8744], "characters": "\u2228" }, - "↻": { "codepoints": [8635], "characters": "\u21BB" }, - "⩝": { "codepoints": [10845], "characters": "\u2A5D" }, - "ℴ": { "codepoints": [8500], "characters": "\u2134" }, - "ℴ": { "codepoints": [8500], "characters": "\u2134" }, - "ª": { "codepoints": [170], "characters": "\u00AA" }, - "ª": { "codepoints": [170], "characters": "\u00AA" }, - "º": { "codepoints": [186], "characters": "\u00BA" }, - "º": { "codepoints": [186], "characters": "\u00BA" }, - "⊶": { "codepoints": [8886], "characters": "\u22B6" }, - "⩖": { "codepoints": [10838], "characters": "\u2A56" }, - "⩗": { "codepoints": [10839], "characters": "\u2A57" }, - "⩛": { "codepoints": [10843], "characters": "\u2A5B" }, - "ℴ": { "codepoints": [8500], "characters": "\u2134" }, - "ø": { "codepoints": [248], "characters": "\u00F8" }, - "ø": { "codepoints": [248], "characters": "\u00F8" }, - "⊘": { "codepoints": [8856], "characters": "\u2298" }, - "õ": { "codepoints": [245], "characters": "\u00F5" }, - "õ": { "codepoints": [245], "characters": "\u00F5" }, - "⊗": { "codepoints": [8855], "characters": "\u2297" }, - "⨶": { "codepoints": [10806], "characters": "\u2A36" }, - "ö": { "codepoints": [246], "characters": "\u00F6" }, - "ö": { "codepoints": [246], "characters": "\u00F6" }, - "⌽": { "codepoints": [9021], "characters": "\u233D" }, - "∥": { "codepoints": [8741], "characters": "\u2225" }, - "¶": { "codepoints": [182], "characters": "\u00B6" }, - "¶": { "codepoints": [182], "characters": "\u00B6" }, - "∥": { "codepoints": [8741], "characters": "\u2225" }, - "⫳": { "codepoints": [10995], "characters": "\u2AF3" }, - "⫽": { "codepoints": [11005], "characters": "\u2AFD" }, - "∂": { "codepoints": [8706], "characters": "\u2202" }, - "п": { "codepoints": [1087], "characters": "\u043F" }, - "%": { "codepoints": [37], "characters": "\u0025" }, - ".": { "codepoints": [46], "characters": "\u002E" }, - "‰": { "codepoints": [8240], "characters": "\u2030" }, - "⊥": { "codepoints": [8869], "characters": "\u22A5" }, - "‱": { "codepoints": [8241], "characters": "\u2031" }, - "𝔭": { "codepoints": [120109], "characters": "\uD835\uDD2D" }, - "φ": { "codepoints": [966], "characters": "\u03C6" }, - "ϕ": { "codepoints": [981], "characters": "\u03D5" }, - "ℳ": { "codepoints": [8499], "characters": "\u2133" }, - "☎": { "codepoints": [9742], "characters": "\u260E" }, - "π": { "codepoints": [960], "characters": "\u03C0" }, - "⋔": { "codepoints": [8916], "characters": "\u22D4" }, - "ϖ": { "codepoints": [982], "characters": "\u03D6" }, - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, - "ℎ": { "codepoints": [8462], "characters": "\u210E" }, - "ℏ": { "codepoints": [8463], "characters": "\u210F" }, - "+": { "codepoints": [43], "characters": "\u002B" }, - "⨣": { "codepoints": [10787], "characters": "\u2A23" }, - "⊞": { "codepoints": [8862], "characters": "\u229E" }, - "⨢": { "codepoints": [10786], "characters": "\u2A22" }, - "∔": { "codepoints": [8724], "characters": "\u2214" }, - "⨥": { "codepoints": [10789], "characters": "\u2A25" }, - "⩲": { "codepoints": [10866], "characters": "\u2A72" }, - "±": { "codepoints": [177], "characters": "\u00B1" }, - "±": { "codepoints": [177], "characters": "\u00B1" }, - "⨦": { "codepoints": [10790], "characters": "\u2A26" }, - "⨧": { "codepoints": [10791], "characters": "\u2A27" }, - "±": { "codepoints": [177], "characters": "\u00B1" }, - "⨕": { "codepoints": [10773], "characters": "\u2A15" }, - "𝕡": { "codepoints": [120161], "characters": "\uD835\uDD61" }, - "£": { "codepoints": [163], "characters": "\u00A3" }, - "£": { "codepoints": [163], "characters": "\u00A3" }, - "≺": { "codepoints": [8826], "characters": "\u227A" }, - "⪳": { "codepoints": [10931], "characters": "\u2AB3" }, - "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, - "≼": { "codepoints": [8828], "characters": "\u227C" }, - "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, - "≺": { "codepoints": [8826], "characters": "\u227A" }, - "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, - "≼": { "codepoints": [8828], "characters": "\u227C" }, - "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, - "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, - "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, - "⋨": { "codepoints": [8936], "characters": "\u22E8" }, - "≾": { "codepoints": [8830], "characters": "\u227E" }, - "′": { "codepoints": [8242], "characters": "\u2032" }, - "ℙ": { "codepoints": [8473], "characters": "\u2119" }, - "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, - "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, - "⋨": { "codepoints": [8936], "characters": "\u22E8" }, - "∏": { "codepoints": [8719], "characters": "\u220F" }, - "⌮": { "codepoints": [9006], "characters": "\u232E" }, - "⌒": { "codepoints": [8978], "characters": "\u2312" }, - "⌓": { "codepoints": [8979], "characters": "\u2313" }, - "∝": { "codepoints": [8733], "characters": "\u221D" }, - "∝": { "codepoints": [8733], "characters": "\u221D" }, - "≾": { "codepoints": [8830], "characters": "\u227E" }, - "⊰": { "codepoints": [8880], "characters": "\u22B0" }, - "𝓅": { "codepoints": [120005], "characters": "\uD835\uDCC5" }, - "ψ": { "codepoints": [968], "characters": "\u03C8" }, - " ": { "codepoints": [8200], "characters": "\u2008" }, - "𝔮": { "codepoints": [120110], "characters": "\uD835\uDD2E" }, - "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, - "𝕢": { "codepoints": [120162], "characters": "\uD835\uDD62" }, - "⁗": { "codepoints": [8279], "characters": "\u2057" }, - "𝓆": { "codepoints": [120006], "characters": "\uD835\uDCC6" }, - "ℍ": { "codepoints": [8461], "characters": "\u210D" }, - "⨖": { "codepoints": [10774], "characters": "\u2A16" }, - "?": { "codepoints": [63], "characters": "\u003F" }, - "≟": { "codepoints": [8799], "characters": "\u225F" }, - """: { "codepoints": [34], "characters": "\u0022" }, - """: { "codepoints": [34], "characters": "\u0022" }, - "⇛": { "codepoints": [8667], "characters": "\u21DB" }, - "⇒": { "codepoints": [8658], "characters": "\u21D2" }, - "⤜": { "codepoints": [10524], "characters": "\u291C" }, - "⤏": { "codepoints": [10511], "characters": "\u290F" }, - "⥤": { "codepoints": [10596], "characters": "\u2964" }, - "∽̱": { "codepoints": [8765, 817], "characters": "\u223D\u0331" }, - "ŕ": { "codepoints": [341], "characters": "\u0155" }, - "√": { "codepoints": [8730], "characters": "\u221A" }, - "⦳": { "codepoints": [10675], "characters": "\u29B3" }, - "⟩": { "codepoints": [10217], "characters": "\u27E9" }, - "⦒": { "codepoints": [10642], "characters": "\u2992" }, - "⦥": { "codepoints": [10661], "characters": "\u29A5" }, - "⟩": { "codepoints": [10217], "characters": "\u27E9" }, - "»": { "codepoints": [187], "characters": "\u00BB" }, - "»": { "codepoints": [187], "characters": "\u00BB" }, - "→": { "codepoints": [8594], "characters": "\u2192" }, - "⥵": { "codepoints": [10613], "characters": "\u2975" }, - "⇥": { "codepoints": [8677], "characters": "\u21E5" }, - "⤠": { "codepoints": [10528], "characters": "\u2920" }, - "⤳": { "codepoints": [10547], "characters": "\u2933" }, - "⤞": { "codepoints": [10526], "characters": "\u291E" }, - "↪": { "codepoints": [8618], "characters": "\u21AA" }, - "↬": { "codepoints": [8620], "characters": "\u21AC" }, - "⥅": { "codepoints": [10565], "characters": "\u2945" }, - "⥴": { "codepoints": [10612], "characters": "\u2974" }, - "↣": { "codepoints": [8611], "characters": "\u21A3" }, - "↝": { "codepoints": [8605], "characters": "\u219D" }, - "⤚": { "codepoints": [10522], "characters": "\u291A" }, - "∶": { "codepoints": [8758], "characters": "\u2236" }, - "ℚ": { "codepoints": [8474], "characters": "\u211A" }, - "⤍": { "codepoints": [10509], "characters": "\u290D" }, - "❳": { "codepoints": [10099], "characters": "\u2773" }, - "}": { "codepoints": [125], "characters": "\u007D" }, - "]": { "codepoints": [93], "characters": "\u005D" }, - "⦌": { "codepoints": [10636], "characters": "\u298C" }, - "⦎": { "codepoints": [10638], "characters": "\u298E" }, - "⦐": { "codepoints": [10640], "characters": "\u2990" }, - "ř": { "codepoints": [345], "characters": "\u0159" }, - "ŗ": { "codepoints": [343], "characters": "\u0157" }, - "⌉": { "codepoints": [8969], "characters": "\u2309" }, - "}": { "codepoints": [125], "characters": "\u007D" }, - "р": { "codepoints": [1088], "characters": "\u0440" }, - "⤷": { "codepoints": [10551], "characters": "\u2937" }, - "⥩": { "codepoints": [10601], "characters": "\u2969" }, - "”": { "codepoints": [8221], "characters": "\u201D" }, - "”": { "codepoints": [8221], "characters": "\u201D" }, - "↳": { "codepoints": [8627], "characters": "\u21B3" }, - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, - "ℛ": { "codepoints": [8475], "characters": "\u211B" }, - "ℜ": { "codepoints": [8476], "characters": "\u211C" }, - "ℝ": { "codepoints": [8477], "characters": "\u211D" }, - "▭": { "codepoints": [9645], "characters": "\u25AD" }, - "®": { "codepoints": [174], "characters": "\u00AE" }, - "®": { "codepoints": [174], "characters": "\u00AE" }, - "⥽": { "codepoints": [10621], "characters": "\u297D" }, - "⌋": { "codepoints": [8971], "characters": "\u230B" }, - "𝔯": { "codepoints": [120111], "characters": "\uD835\uDD2F" }, - "⇁": { "codepoints": [8641], "characters": "\u21C1" }, - "⇀": { "codepoints": [8640], "characters": "\u21C0" }, - "⥬": { "codepoints": [10604], "characters": "\u296C" }, - "ρ": { "codepoints": [961], "characters": "\u03C1" }, - "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, - "→": { "codepoints": [8594], "characters": "\u2192" }, - "↣": { "codepoints": [8611], "characters": "\u21A3" }, - "⇁": { "codepoints": [8641], "characters": "\u21C1" }, - "⇀": { "codepoints": [8640], "characters": "\u21C0" }, - "⇄": { "codepoints": [8644], "characters": "\u21C4" }, - "⇌": { "codepoints": [8652], "characters": "\u21CC" }, - "⇉": { "codepoints": [8649], "characters": "\u21C9" }, - "↝": { "codepoints": [8605], "characters": "\u219D" }, - "⋌": { "codepoints": [8908], "characters": "\u22CC" }, - "˚": { "codepoints": [730], "characters": "\u02DA" }, - "≓": { "codepoints": [8787], "characters": "\u2253" }, - "⇄": { "codepoints": [8644], "characters": "\u21C4" }, - "⇌": { "codepoints": [8652], "characters": "\u21CC" }, - "‏": { "codepoints": [8207], "characters": "\u200F" }, - "⎱": { "codepoints": [9137], "characters": "\u23B1" }, - "⎱": { "codepoints": [9137], "characters": "\u23B1" }, - "⫮": { "codepoints": [10990], "characters": "\u2AEE" }, - "⟭": { "codepoints": [10221], "characters": "\u27ED" }, - "⇾": { "codepoints": [8702], "characters": "\u21FE" }, - "⟧": { "codepoints": [10215], "characters": "\u27E7" }, - "⦆": { "codepoints": [10630], "characters": "\u2986" }, - "𝕣": { "codepoints": [120163], "characters": "\uD835\uDD63" }, - "⨮": { "codepoints": [10798], "characters": "\u2A2E" }, - "⨵": { "codepoints": [10805], "characters": "\u2A35" }, - ")": { "codepoints": [41], "characters": "\u0029" }, - "⦔": { "codepoints": [10644], "characters": "\u2994" }, - "⨒": { "codepoints": [10770], "characters": "\u2A12" }, - "⇉": { "codepoints": [8649], "characters": "\u21C9" }, - "›": { "codepoints": [8250], "characters": "\u203A" }, - "𝓇": { "codepoints": [120007], "characters": "\uD835\uDCC7" }, - "↱": { "codepoints": [8625], "characters": "\u21B1" }, - "]": { "codepoints": [93], "characters": "\u005D" }, - "’": { "codepoints": [8217], "characters": "\u2019" }, - "’": { "codepoints": [8217], "characters": "\u2019" }, - "⋌": { "codepoints": [8908], "characters": "\u22CC" }, - "⋊": { "codepoints": [8906], "characters": "\u22CA" }, - "▹": { "codepoints": [9657], "characters": "\u25B9" }, - "⊵": { "codepoints": [8885], "characters": "\u22B5" }, - "▸": { "codepoints": [9656], "characters": "\u25B8" }, - "⧎": { "codepoints": [10702], "characters": "\u29CE" }, - "⥨": { "codepoints": [10600], "characters": "\u2968" }, - "℞": { "codepoints": [8478], "characters": "\u211E" }, - "ś": { "codepoints": [347], "characters": "\u015B" }, - "‚": { "codepoints": [8218], "characters": "\u201A" }, - "≻": { "codepoints": [8827], "characters": "\u227B" }, - "⪴": { "codepoints": [10932], "characters": "\u2AB4" }, - "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, - "š": { "codepoints": [353], "characters": "\u0161" }, - "≽": { "codepoints": [8829], "characters": "\u227D" }, - "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, - "ş": { "codepoints": [351], "characters": "\u015F" }, - "ŝ": { "codepoints": [349], "characters": "\u015D" }, - "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, - "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, - "⋩": { "codepoints": [8937], "characters": "\u22E9" }, - "⨓": { "codepoints": [10771], "characters": "\u2A13" }, - "≿": { "codepoints": [8831], "characters": "\u227F" }, - "с": { "codepoints": [1089], "characters": "\u0441" }, - "⋅": { "codepoints": [8901], "characters": "\u22C5" }, - "⊡": { "codepoints": [8865], "characters": "\u22A1" }, - "⩦": { "codepoints": [10854], "characters": "\u2A66" }, - "⇘": { "codepoints": [8664], "characters": "\u21D8" }, - "⤥": { "codepoints": [10533], "characters": "\u2925" }, - "↘": { "codepoints": [8600], "characters": "\u2198" }, - "↘": { "codepoints": [8600], "characters": "\u2198" }, - "§": { "codepoints": [167], "characters": "\u00A7" }, - "§": { "codepoints": [167], "characters": "\u00A7" }, - ";": { "codepoints": [59], "characters": "\u003B" }, - "⤩": { "codepoints": [10537], "characters": "\u2929" }, - "∖": { "codepoints": [8726], "characters": "\u2216" }, - "∖": { "codepoints": [8726], "characters": "\u2216" }, - "✶": { "codepoints": [10038], "characters": "\u2736" }, - "𝔰": { "codepoints": [120112], "characters": "\uD835\uDD30" }, - "⌢": { "codepoints": [8994], "characters": "\u2322" }, - "♯": { "codepoints": [9839], "characters": "\u266F" }, - "щ": { "codepoints": [1097], "characters": "\u0449" }, - "ш": { "codepoints": [1096], "characters": "\u0448" }, - "∣": { "codepoints": [8739], "characters": "\u2223" }, - "∥": { "codepoints": [8741], "characters": "\u2225" }, - "­": { "codepoints": [173], "characters": "\u00AD" }, - "­": { "codepoints": [173], "characters": "\u00AD" }, - "σ": { "codepoints": [963], "characters": "\u03C3" }, - "ς": { "codepoints": [962], "characters": "\u03C2" }, - "ς": { "codepoints": [962], "characters": "\u03C2" }, - "∼": { "codepoints": [8764], "characters": "\u223C" }, - "⩪": { "codepoints": [10858], "characters": "\u2A6A" }, - "≃": { "codepoints": [8771], "characters": "\u2243" }, - "≃": { "codepoints": [8771], "characters": "\u2243" }, - "⪞": { "codepoints": [10910], "characters": "\u2A9E" }, - "⪠": { "codepoints": [10912], "characters": "\u2AA0" }, - "⪝": { "codepoints": [10909], "characters": "\u2A9D" }, - "⪟": { "codepoints": [10911], "characters": "\u2A9F" }, - "≆": { "codepoints": [8774], "characters": "\u2246" }, - "⨤": { "codepoints": [10788], "characters": "\u2A24" }, - "⥲": { "codepoints": [10610], "characters": "\u2972" }, - "←": { "codepoints": [8592], "characters": "\u2190" }, - "∖": { "codepoints": [8726], "characters": "\u2216" }, - "⨳": { "codepoints": [10803], "characters": "\u2A33" }, - "⧤": { "codepoints": [10724], "characters": "\u29E4" }, - "∣": { "codepoints": [8739], "characters": "\u2223" }, - "⌣": { "codepoints": [8995], "characters": "\u2323" }, - "⪪": { "codepoints": [10922], "characters": "\u2AAA" }, - "⪬": { "codepoints": [10924], "characters": "\u2AAC" }, - "⪬︀": { "codepoints": [10924, 65024], "characters": "\u2AAC\uFE00" }, - "ь": { "codepoints": [1100], "characters": "\u044C" }, - "/": { "codepoints": [47], "characters": "\u002F" }, - "⧄": { "codepoints": [10692], "characters": "\u29C4" }, - "⌿": { "codepoints": [9023], "characters": "\u233F" }, - "𝕤": { "codepoints": [120164], "characters": "\uD835\uDD64" }, - "♠": { "codepoints": [9824], "characters": "\u2660" }, - "♠": { "codepoints": [9824], "characters": "\u2660" }, - "∥": { "codepoints": [8741], "characters": "\u2225" }, - "⊓": { "codepoints": [8851], "characters": "\u2293" }, - "⊓︀": { "codepoints": [8851, 65024], "characters": "\u2293\uFE00" }, - "⊔": { "codepoints": [8852], "characters": "\u2294" }, - "⊔︀": { "codepoints": [8852, 65024], "characters": "\u2294\uFE00" }, - "⊏": { "codepoints": [8847], "characters": "\u228F" }, - "⊑": { "codepoints": [8849], "characters": "\u2291" }, - "⊏": { "codepoints": [8847], "characters": "\u228F" }, - "⊑": { "codepoints": [8849], "characters": "\u2291" }, - "⊐": { "codepoints": [8848], "characters": "\u2290" }, - "⊒": { "codepoints": [8850], "characters": "\u2292" }, - "⊐": { "codepoints": [8848], "characters": "\u2290" }, - "⊒": { "codepoints": [8850], "characters": "\u2292" }, - "□": { "codepoints": [9633], "characters": "\u25A1" }, - "□": { "codepoints": [9633], "characters": "\u25A1" }, - "▪": { "codepoints": [9642], "characters": "\u25AA" }, - "▪": { "codepoints": [9642], "characters": "\u25AA" }, - "→": { "codepoints": [8594], "characters": "\u2192" }, - "𝓈": { "codepoints": [120008], "characters": "\uD835\uDCC8" }, - "∖": { "codepoints": [8726], "characters": "\u2216" }, - "⌣": { "codepoints": [8995], "characters": "\u2323" }, - "⋆": { "codepoints": [8902], "characters": "\u22C6" }, - "☆": { "codepoints": [9734], "characters": "\u2606" }, - "★": { "codepoints": [9733], "characters": "\u2605" }, - "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, - "ϕ": { "codepoints": [981], "characters": "\u03D5" }, - "¯": { "codepoints": [175], "characters": "\u00AF" }, - "⊂": { "codepoints": [8834], "characters": "\u2282" }, - "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, - "⪽": { "codepoints": [10941], "characters": "\u2ABD" }, - "⊆": { "codepoints": [8838], "characters": "\u2286" }, - "⫃": { "codepoints": [10947], "characters": "\u2AC3" }, - "⫁": { "codepoints": [10945], "characters": "\u2AC1" }, - "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, - "⊊": { "codepoints": [8842], "characters": "\u228A" }, - "⪿": { "codepoints": [10943], "characters": "\u2ABF" }, - "⥹": { "codepoints": [10617], "characters": "\u2979" }, - "⊂": { "codepoints": [8834], "characters": "\u2282" }, - "⊆": { "codepoints": [8838], "characters": "\u2286" }, - "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, - "⊊": { "codepoints": [8842], "characters": "\u228A" }, - "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, - "⫇": { "codepoints": [10951], "characters": "\u2AC7" }, - "⫕": { "codepoints": [10965], "characters": "\u2AD5" }, - "⫓": { "codepoints": [10963], "characters": "\u2AD3" }, - "≻": { "codepoints": [8827], "characters": "\u227B" }, - "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, - "≽": { "codepoints": [8829], "characters": "\u227D" }, - "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, - "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, - "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, - "⋩": { "codepoints": [8937], "characters": "\u22E9" }, - "≿": { "codepoints": [8831], "characters": "\u227F" }, - "∑": { "codepoints": [8721], "characters": "\u2211" }, - "♪": { "codepoints": [9834], "characters": "\u266A" }, - "¹": { "codepoints": [185], "characters": "\u00B9" }, - "¹": { "codepoints": [185], "characters": "\u00B9" }, - "²": { "codepoints": [178], "characters": "\u00B2" }, - "²": { "codepoints": [178], "characters": "\u00B2" }, - "³": { "codepoints": [179], "characters": "\u00B3" }, - "³": { "codepoints": [179], "characters": "\u00B3" }, - "⊃": { "codepoints": [8835], "characters": "\u2283" }, - "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, - "⪾": { "codepoints": [10942], "characters": "\u2ABE" }, - "⫘": { "codepoints": [10968], "characters": "\u2AD8" }, - "⊇": { "codepoints": [8839], "characters": "\u2287" }, - "⫄": { "codepoints": [10948], "characters": "\u2AC4" }, - "⟉": { "codepoints": [10185], "characters": "\u27C9" }, - "⫗": { "codepoints": [10967], "characters": "\u2AD7" }, - "⥻": { "codepoints": [10619], "characters": "\u297B" }, - "⫂": { "codepoints": [10946], "characters": "\u2AC2" }, - "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, - "⊋": { "codepoints": [8843], "characters": "\u228B" }, - "⫀": { "codepoints": [10944], "characters": "\u2AC0" }, - "⊃": { "codepoints": [8835], "characters": "\u2283" }, - "⊇": { "codepoints": [8839], "characters": "\u2287" }, - "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, - "⊋": { "codepoints": [8843], "characters": "\u228B" }, - "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, - "⫈": { "codepoints": [10952], "characters": "\u2AC8" }, - "⫔": { "codepoints": [10964], "characters": "\u2AD4" }, - "⫖": { "codepoints": [10966], "characters": "\u2AD6" }, - "⇙": { "codepoints": [8665], "characters": "\u21D9" }, - "⤦": { "codepoints": [10534], "characters": "\u2926" }, - "↙": { "codepoints": [8601], "characters": "\u2199" }, - "↙": { "codepoints": [8601], "characters": "\u2199" }, - "⤪": { "codepoints": [10538], "characters": "\u292A" }, - "ß": { "codepoints": [223], "characters": "\u00DF" }, - "ß": { "codepoints": [223], "characters": "\u00DF" }, - "⌖": { "codepoints": [8982], "characters": "\u2316" }, - "τ": { "codepoints": [964], "characters": "\u03C4" }, - "⎴": { "codepoints": [9140], "characters": "\u23B4" }, - "ť": { "codepoints": [357], "characters": "\u0165" }, - "ţ": { "codepoints": [355], "characters": "\u0163" }, - "т": { "codepoints": [1090], "characters": "\u0442" }, - "⃛": { "codepoints": [8411], "characters": "\u20DB" }, - "⌕": { "codepoints": [8981], "characters": "\u2315" }, - "𝔱": { "codepoints": [120113], "characters": "\uD835\uDD31" }, - "∴": { "codepoints": [8756], "characters": "\u2234" }, - "∴": { "codepoints": [8756], "characters": "\u2234" }, - "θ": { "codepoints": [952], "characters": "\u03B8" }, - "ϑ": { "codepoints": [977], "characters": "\u03D1" }, - "ϑ": { "codepoints": [977], "characters": "\u03D1" }, - "≈": { "codepoints": [8776], "characters": "\u2248" }, - "∼": { "codepoints": [8764], "characters": "\u223C" }, - " ": { "codepoints": [8201], "characters": "\u2009" }, - "≈": { "codepoints": [8776], "characters": "\u2248" }, - "∼": { "codepoints": [8764], "characters": "\u223C" }, - "þ": { "codepoints": [254], "characters": "\u00FE" }, - "þ": { "codepoints": [254], "characters": "\u00FE" }, - "˜": { "codepoints": [732], "characters": "\u02DC" }, - "×": { "codepoints": [215], "characters": "\u00D7" }, - "×": { "codepoints": [215], "characters": "\u00D7" }, - "⊠": { "codepoints": [8864], "characters": "\u22A0" }, - "⨱": { "codepoints": [10801], "characters": "\u2A31" }, - "⨰": { "codepoints": [10800], "characters": "\u2A30" }, - "∭": { "codepoints": [8749], "characters": "\u222D" }, - "⤨": { "codepoints": [10536], "characters": "\u2928" }, - "⊤": { "codepoints": [8868], "characters": "\u22A4" }, - "⌶": { "codepoints": [9014], "characters": "\u2336" }, - "⫱": { "codepoints": [10993], "characters": "\u2AF1" }, - "𝕥": { "codepoints": [120165], "characters": "\uD835\uDD65" }, - "⫚": { "codepoints": [10970], "characters": "\u2ADA" }, - "⤩": { "codepoints": [10537], "characters": "\u2929" }, - "‴": { "codepoints": [8244], "characters": "\u2034" }, - "™": { "codepoints": [8482], "characters": "\u2122" }, - "▵": { "codepoints": [9653], "characters": "\u25B5" }, - "▿": { "codepoints": [9663], "characters": "\u25BF" }, - "◃": { "codepoints": [9667], "characters": "\u25C3" }, - "⊴": { "codepoints": [8884], "characters": "\u22B4" }, - "≜": { "codepoints": [8796], "characters": "\u225C" }, - "▹": { "codepoints": [9657], "characters": "\u25B9" }, - "⊵": { "codepoints": [8885], "characters": "\u22B5" }, - "◬": { "codepoints": [9708], "characters": "\u25EC" }, - "≜": { "codepoints": [8796], "characters": "\u225C" }, - "⨺": { "codepoints": [10810], "characters": "\u2A3A" }, - "⨹": { "codepoints": [10809], "characters": "\u2A39" }, - "⧍": { "codepoints": [10701], "characters": "\u29CD" }, - "⨻": { "codepoints": [10811], "characters": "\u2A3B" }, - "⏢": { "codepoints": [9186], "characters": "\u23E2" }, - "𝓉": { "codepoints": [120009], "characters": "\uD835\uDCC9" }, - "ц": { "codepoints": [1094], "characters": "\u0446" }, - "ћ": { "codepoints": [1115], "characters": "\u045B" }, - "ŧ": { "codepoints": [359], "characters": "\u0167" }, - "≬": { "codepoints": [8812], "characters": "\u226C" }, - "↞": { "codepoints": [8606], "characters": "\u219E" }, - "↠": { "codepoints": [8608], "characters": "\u21A0" }, - "⇑": { "codepoints": [8657], "characters": "\u21D1" }, - "⥣": { "codepoints": [10595], "characters": "\u2963" }, - "ú": { "codepoints": [250], "characters": "\u00FA" }, - "ú": { "codepoints": [250], "characters": "\u00FA" }, - "↑": { "codepoints": [8593], "characters": "\u2191" }, - "ў": { "codepoints": [1118], "characters": "\u045E" }, - "ŭ": { "codepoints": [365], "characters": "\u016D" }, - "û": { "codepoints": [251], "characters": "\u00FB" }, - "û": { "codepoints": [251], "characters": "\u00FB" }, - "у": { "codepoints": [1091], "characters": "\u0443" }, - "⇅": { "codepoints": [8645], "characters": "\u21C5" }, - "ű": { "codepoints": [369], "characters": "\u0171" }, - "⥮": { "codepoints": [10606], "characters": "\u296E" }, - "⥾": { "codepoints": [10622], "characters": "\u297E" }, - "𝔲": { "codepoints": [120114], "characters": "\uD835\uDD32" }, - "ù": { "codepoints": [249], "characters": "\u00F9" }, - "ù": { "codepoints": [249], "characters": "\u00F9" }, - "↿": { "codepoints": [8639], "characters": "\u21BF" }, - "↾": { "codepoints": [8638], "characters": "\u21BE" }, - "▀": { "codepoints": [9600], "characters": "\u2580" }, - "⌜": { "codepoints": [8988], "characters": "\u231C" }, - "⌜": { "codepoints": [8988], "characters": "\u231C" }, - "⌏": { "codepoints": [8975], "characters": "\u230F" }, - "◸": { "codepoints": [9720], "characters": "\u25F8" }, - "ū": { "codepoints": [363], "characters": "\u016B" }, - "¨": { "codepoints": [168], "characters": "\u00A8" }, - "¨": { "codepoints": [168], "characters": "\u00A8" }, - "ų": { "codepoints": [371], "characters": "\u0173" }, - "𝕦": { "codepoints": [120166], "characters": "\uD835\uDD66" }, - "↑": { "codepoints": [8593], "characters": "\u2191" }, - "↕": { "codepoints": [8597], "characters": "\u2195" }, - "↿": { "codepoints": [8639], "characters": "\u21BF" }, - "↾": { "codepoints": [8638], "characters": "\u21BE" }, - "⊎": { "codepoints": [8846], "characters": "\u228E" }, - "υ": { "codepoints": [965], "characters": "\u03C5" }, - "ϒ": { "codepoints": [978], "characters": "\u03D2" }, - "υ": { "codepoints": [965], "characters": "\u03C5" }, - "⇈": { "codepoints": [8648], "characters": "\u21C8" }, - "⌝": { "codepoints": [8989], "characters": "\u231D" }, - "⌝": { "codepoints": [8989], "characters": "\u231D" }, - "⌎": { "codepoints": [8974], "characters": "\u230E" }, - "ů": { "codepoints": [367], "characters": "\u016F" }, - "◹": { "codepoints": [9721], "characters": "\u25F9" }, - "𝓊": { "codepoints": [120010], "characters": "\uD835\uDCCA" }, - "⋰": { "codepoints": [8944], "characters": "\u22F0" }, - "ũ": { "codepoints": [361], "characters": "\u0169" }, - "▵": { "codepoints": [9653], "characters": "\u25B5" }, - "▴": { "codepoints": [9652], "characters": "\u25B4" }, - "⇈": { "codepoints": [8648], "characters": "\u21C8" }, - "ü": { "codepoints": [252], "characters": "\u00FC" }, - "ü": { "codepoints": [252], "characters": "\u00FC" }, - "⦧": { "codepoints": [10663], "characters": "\u29A7" }, - "⇕": { "codepoints": [8661], "characters": "\u21D5" }, - "⫨": { "codepoints": [10984], "characters": "\u2AE8" }, - "⫩": { "codepoints": [10985], "characters": "\u2AE9" }, - "⊨": { "codepoints": [8872], "characters": "\u22A8" }, - "⦜": { "codepoints": [10652], "characters": "\u299C" }, - "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, - "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, - "∅": { "codepoints": [8709], "characters": "\u2205" }, - "ϕ": { "codepoints": [981], "characters": "\u03D5" }, - "ϖ": { "codepoints": [982], "characters": "\u03D6" }, - "∝": { "codepoints": [8733], "characters": "\u221D" }, - "↕": { "codepoints": [8597], "characters": "\u2195" }, - "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, - "ς": { "codepoints": [962], "characters": "\u03C2" }, - "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, - "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, - "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, - "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, - "ϑ": { "codepoints": [977], "characters": "\u03D1" }, - "⊲": { "codepoints": [8882], "characters": "\u22B2" }, - "⊳": { "codepoints": [8883], "characters": "\u22B3" }, - "в": { "codepoints": [1074], "characters": "\u0432" }, - "⊢": { "codepoints": [8866], "characters": "\u22A2" }, - "∨": { "codepoints": [8744], "characters": "\u2228" }, - "⊻": { "codepoints": [8891], "characters": "\u22BB" }, - "≚": { "codepoints": [8794], "characters": "\u225A" }, - "⋮": { "codepoints": [8942], "characters": "\u22EE" }, - "|": { "codepoints": [124], "characters": "\u007C" }, - "|": { "codepoints": [124], "characters": "\u007C" }, - "𝔳": { "codepoints": [120115], "characters": "\uD835\uDD33" }, - "⊲": { "codepoints": [8882], "characters": "\u22B2" }, - "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, - "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, - "𝕧": { "codepoints": [120167], "characters": "\uD835\uDD67" }, - "∝": { "codepoints": [8733], "characters": "\u221D" }, - "⊳": { "codepoints": [8883], "characters": "\u22B3" }, - "𝓋": { "codepoints": [120011], "characters": "\uD835\uDCCB" }, - "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, - "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, - "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, - "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, - "⦚": { "codepoints": [10650], "characters": "\u299A" }, - "ŵ": { "codepoints": [373], "characters": "\u0175" }, - "⩟": { "codepoints": [10847], "characters": "\u2A5F" }, - "∧": { "codepoints": [8743], "characters": "\u2227" }, - "≙": { "codepoints": [8793], "characters": "\u2259" }, - "℘": { "codepoints": [8472], "characters": "\u2118" }, - "𝔴": { "codepoints": [120116], "characters": "\uD835\uDD34" }, - "𝕨": { "codepoints": [120168], "characters": "\uD835\uDD68" }, - "℘": { "codepoints": [8472], "characters": "\u2118" }, - "≀": { "codepoints": [8768], "characters": "\u2240" }, - "≀": { "codepoints": [8768], "characters": "\u2240" }, - "𝓌": { "codepoints": [120012], "characters": "\uD835\uDCCC" }, - "⋂": { "codepoints": [8898], "characters": "\u22C2" }, - "◯": { "codepoints": [9711], "characters": "\u25EF" }, - "⋃": { "codepoints": [8899], "characters": "\u22C3" }, - "▽": { "codepoints": [9661], "characters": "\u25BD" }, - "𝔵": { "codepoints": [120117], "characters": "\uD835\uDD35" }, - "⟺": { "codepoints": [10234], "characters": "\u27FA" }, - "⟷": { "codepoints": [10231], "characters": "\u27F7" }, - "ξ": { "codepoints": [958], "characters": "\u03BE" }, - "⟸": { "codepoints": [10232], "characters": "\u27F8" }, - "⟵": { "codepoints": [10229], "characters": "\u27F5" }, - "⟼": { "codepoints": [10236], "characters": "\u27FC" }, - "⋻": { "codepoints": [8955], "characters": "\u22FB" }, - "⨀": { "codepoints": [10752], "characters": "\u2A00" }, - "𝕩": { "codepoints": [120169], "characters": "\uD835\uDD69" }, - "⨁": { "codepoints": [10753], "characters": "\u2A01" }, - "⨂": { "codepoints": [10754], "characters": "\u2A02" }, - "⟹": { "codepoints": [10233], "characters": "\u27F9" }, - "⟶": { "codepoints": [10230], "characters": "\u27F6" }, - "𝓍": { "codepoints": [120013], "characters": "\uD835\uDCCD" }, - "⨆": { "codepoints": [10758], "characters": "\u2A06" }, - "⨄": { "codepoints": [10756], "characters": "\u2A04" }, - "△": { "codepoints": [9651], "characters": "\u25B3" }, - "⋁": { "codepoints": [8897], "characters": "\u22C1" }, - "⋀": { "codepoints": [8896], "characters": "\u22C0" }, - "ý": { "codepoints": [253], "characters": "\u00FD" }, - "ý": { "codepoints": [253], "characters": "\u00FD" }, - "я": { "codepoints": [1103], "characters": "\u044F" }, - "ŷ": { "codepoints": [375], "characters": "\u0177" }, - "ы": { "codepoints": [1099], "characters": "\u044B" }, - "¥": { "codepoints": [165], "characters": "\u00A5" }, - "¥": { "codepoints": [165], "characters": "\u00A5" }, - "𝔶": { "codepoints": [120118], "characters": "\uD835\uDD36" }, - "ї": { "codepoints": [1111], "characters": "\u0457" }, - "𝕪": { "codepoints": [120170], "characters": "\uD835\uDD6A" }, - "𝓎": { "codepoints": [120014], "characters": "\uD835\uDCCE" }, - "ю": { "codepoints": [1102], "characters": "\u044E" }, - "ÿ": { "codepoints": [255], "characters": "\u00FF" }, - "ÿ": { "codepoints": [255], "characters": "\u00FF" }, - "ź": { "codepoints": [378], "characters": "\u017A" }, - "ž": { "codepoints": [382], "characters": "\u017E" }, - "з": { "codepoints": [1079], "characters": "\u0437" }, - "ż": { "codepoints": [380], "characters": "\u017C" }, - "ℨ": { "codepoints": [8488], "characters": "\u2128" }, - "ζ": { "codepoints": [950], "characters": "\u03B6" }, - "𝔷": { "codepoints": [120119], "characters": "\uD835\uDD37" }, - "ж": { "codepoints": [1078], "characters": "\u0436" }, - "⇝": { "codepoints": [8669], "characters": "\u21DD" }, - "𝕫": { "codepoints": [120171], "characters": "\uD835\uDD6B" }, - "𝓏": { "codepoints": [120015], "characters": "\uD835\uDCCF" }, - "‍": { "codepoints": [8205], "characters": "\u200D" }, - "‌": { "codepoints": [8204], "characters": "\u200C" } -} diff --git a/enums.nim b/enums.nim deleted file mode 100644 index 5b765d01..00000000 --- a/enums.nim +++ /dev/null @@ -1,93 +0,0 @@ -type - NodeType* = - enum - UNKNOWN_NODE = 0, - ELEMENT_NODE = 1, - ATTRIBUTE_NODE = 2, - TEXT_NODE = 3, - CDATA_SECTION_NODE = 4, - ENTITY_REFERENCE_NODE = 5, - ENTITY_NODE = 6 - PROCESSING_INSTRUCTION_NODE = 7, - COMMENT_NODE = 8, - DOCUMENT_NODE = 9, - DOCUMENT_TYPE_NODE = 10, - DOCUMENT_FRAGMENT_NODE = 11, - NOTATION_NODE = 12 - - DisplayType* = - enum - DISPLAY_INLINE, DISPLAY_BLOCK, DISPLAY_LIST_ITEM, DISPLAY_TABLE_COLUMN, - DISPLAY_INLINE_BLOCK, DISPLAY_NONE - - InputType* = - enum - INPUT_UNKNOWN, INPUT_BUTTON, INPUT_CHECKBOX, INPUT_COLOR, INPUT_DATE, - INPUT_DATETIME_LOCAL, INPUT_EMAIL, INPUT_FILE, INPUT_HIDDEN, INPUT_IMAGE, - INPUT_MONTH, INPUT_NUMBER, INPUT_PASSWORD, INPUT_RADIO, INPUT_RANGE, - INPUT_RESET, INPUT_SEARCH, INPUT_SUBMIT, INPUT_TEL, INPUT_TEXT, INPUT_TIME, - INPUT_URL, INPUT_WEEK - - WhitespaceType* = - enum - WHITESPACE_UNKNOWN, WHITESPACE_NORMAL, WHITESPACE_NOWRAP, WHITESPACE_PRE, - WHITESPACE_PRE_LINE, WHITESPACE_PRE_WRAP, WHITESPACE_INITIAL, - WHITESPACE_INHERIT - - TagType* = - enum - TAG_UNKNOWN, TAG_HTML, TAG_BASE, TAG_HEAD, TAG_LINK, TAG_META, TAG_STYLE, - TAG_TITLE, TAG_BODY, TAG_ADDRESS, TAG_ARTICLE, TAG_ASIDE, TAG_FOOTER, - TAG_HEADER, TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6, TAG_HGROUP, - TAG_MAIN, TAG_NAV, TAG_SECTION, TAG_BLOCKQUOTE, TAG_DD, TAG_DIV, TAG_DL, - TAG_DT, TAG_FIGCAPTION, TAG_FIGURE, TAG_HR, TAG_LI, TAG_OL, TAG_P, TAG_PRE, - TAG_UL, TAG_A, TAG_ABBR, TAG_B, TAG_BDI, TAG_BDO, TAG_BR, TAG_CITE, - TAG_CODE, TAG_DATA, TAG_DFN, TAG_EM, TAG_I, TAG_KBD, TAG_MARK, TAG_Q, - TAG_RB, TAG_RP, TAG_RT, TAG_RTC, TAG_RUBY, TAG_S, TAG_SAMP, TAG_SMALL, - TAG_SPAN, TAG_STRONG, TAG_SUB, TAG_SUP, TAG_TIME, TAG_U, TAG_VAR, TAG_WBR, - TAG_AREA, TAG_AUDIO, TAG_IMG, TAG_MAP, TAG_TRACK, TAG_VIDEO, - TAG_IFRAME, TAG_OBJECT, TAG_PARAM, TAG_PICTURE, TAG_PORTAL, TAG_SOURCE, - TAG_CANVAS, TAG_NOSCRIPT, TAG_SCRIPT, TAG_DEL, TAG_INS, TAG_CAPTION, - TAG_COL, TAG_COLGROUP, TAG_TABLE, TAG_TBODY, TAG_TD, TAG_TFOOT, TAG_TH, - TAG_THEAD, TAG_TR, TAG_BUTTON, TAG_DATALIST, TAG_FIELDSET, TAG_FORM, - TAG_INPUT, TAG_LABEL, TAG_LEGEND, TAG_METER, TAG_OPTGROUP, TAG_OPTION, - TAG_OUTPUT, TAG_PROGRESS, TAG_SELECT, TAG_TEXTAREA, TAG_DETAILS, - TAG_DIALOG, TAG_MENU, TAG_SUMMARY, TAG_BLINK, TAG_CENTER, TAG_CONTENT, - TAG_DIR, TAG_FONT, TAG_FRAME, TAG_NOFRAMES, TAG_FRAMESET, TAG_STRIKE, TAG_TT - -const DisplayInlineTags* = { - TAG_A, TAG_ABBR, TAG_B, TAG_BDO, TAG_BR, TAG_BUTTON, TAG_CITE, TAG_CODE, - TAG_DEL, TAG_DFN, TAG_EM, TAG_FONT, TAG_I, TAG_IMG, TAG_INS, TAG_INPUT, - TAG_IFRAME, TAG_KBD, TAG_LABEL, TAG_MAP, TAG_OBJECT, TAG_Q, TAG_SAMP, - TAG_SCRIPT, TAG_SELECT, TAG_SMALL, TAG_SPAN, TAG_STRONG, TAG_SUB, TAG_SUP, - TAG_TEXTAREA, TAG_TT, TAG_VAR, TAG_FONT, TAG_IFRAME, TAG_U, TAG_S, TAG_STRIKE, - TAG_FRAME, TAG_IMG, TAG_INPUT -} - -const DisplayNoneTags* = { - TAG_AREA, TAG_BASE, TAG_SOURCE, TAG_TRACK, TAG_LINK, TAG_META, TAG_PARAM, TAG_WBR -} - -const DisplayInlineBlockTags* = { - TAG_IMG -} - -const DisplayTableColumnTags* = { - TAG_COL -} - -const DisplayBlockTags* = { - TAG_ADDRESS, TAG_BLOCKQUOTE, TAG_CENTER, TAG_DEL, TAG_DIR, TAG_DIV, TAG_DL, - TAG_FIELDSET, TAG_FORM, TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6, - TAG_HR, TAG_INS, TAG_MENU, TAG_NOFRAMES, TAG_NOSCRIPT, TAG_OL, TAG_P, TAG_PRE, - TAG_TABLE, TAG_UL, TAG_CENTER, TAG_DIR, TAG_MENU, TAG_NOFRAMES, TAG_BODY, -} - -const SelfClosingTagTypes* = { - TAG_LI, TAG_P -} - -const VoidTagTypes* = { - TAG_AREA, TAG_BASE, TAG_BR, TAG_COL, TAG_FRAME, TAG_HR, TAG_IMG, TAG_INPUT, - TAG_SOURCE, TAG_TRACK, TAG_LINK, TAG_META, TAG_PARAM, TAG_WBR, TAG_HR -} diff --git a/main.nim b/main.nim deleted file mode 100644 index 677b812f..00000000 --- a/main.nim +++ /dev/null @@ -1,65 +0,0 @@ -import httpClient -import uri -import os -import streams - -import display -import termattrs -import buffer -import twtio -import config -import parser - -let clientInstance = newHttpClient() -proc loadRemotePage*(url: string): string = - return clientInstance.getContent(url) - -proc loadLocalPage*(url: string): string = - return readFile(url) - -proc getRemotePage*(url: string): Stream = - return clientInstance.get(url).bodyStream - -proc getLocalPage*(url: string): Stream = - return newFileStream(url, fmRead) - -proc getPageUri(uri: Uri): Stream = - var moduri = uri - moduri.anchor = "" - if uri.scheme == "" or uri.scheme == "file": - return getLocalPage($moduri) - else: - return getRemotePage($moduri) - -var buffers: seq[Buffer] - -proc main*() = - if paramCount() != 1: - eprint "Invalid parameters. Usage:\ntwt " - quit(1) - if not readConfig("config"): - eprint "Failed to read keymap, falling back to default" - let attrs = getTermAttributes() - let buffer = newBuffer(attrs) - let uri = parseUri(paramStr(1)) - buffers.add(buffer) - buffer.document = parseHtml(getPageUri(uri)) - buffer.setLocation(uri) - buffer.renderHtml() - var lastUri = uri - while displayPage(attrs, buffer): - statusMsg("Loading...", buffer.height) - var newUri = buffer.document.location - lastUri.anchor = "" - newUri.anchor = "" - if $lastUri != $newUri: - buffer.clearBuffer() - if uri.scheme == "" and uri.path == "" and uri.anchor != "": - discard - else: - buffer.document = parseHtml(getPageUri(buffer.document.location)) - buffer.renderHtml() - lastUri = newUri - -#waitFor loadPage("https://lite.duckduckgo.com/lite/?q=hello%20world") -main() diff --git a/parser.nim b/parser.nim deleted file mode 100644 index 11c39c76..00000000 --- a/parser.nim +++ /dev/null @@ -1,498 +0,0 @@ -import streams -import unicode -import strutils -import tables -import json - -import twtio -import enums -import twtstr -import dom -import radixtree - -type - ParseState = object - stream: Stream - closed: bool - parents: seq[Node] - parsedNode: Node - a: string - b: string - attrs: seq[string] - in_comment: bool - in_script: bool - in_style: bool - in_noscript: bool - parentNode: Node - textNode: Text - -#func newHtmlElement(tagType: TagType, parentNode: Node): HtmlElement = -# case tagType -# of TAG_INPUT: result = new(HtmlInputElement) -# of TAG_A: result = new(HtmlAnchorElement) -# of TAG_SELECT: result = new(HtmlSelectElement) -# of TAG_OPTION: result = new(HtmlOptionElement) -# else: result = new(HtmlElement) -# -# result.nodeType = ELEMENT_NODE -# result.tagType = tagType -# result.parentNode = parentNode -# if parentNode.isElemNode(): -# result.parentElement = HtmlElement(parentNode) -# -# if tagType in DisplayInlineTags: -# result.display = DISPLAY_INLINE -# elif tagType in DisplayBlockTags: -# result.display = DISPLAY_BLOCK -# elif tagType in DisplayInlineBlockTags: -# result.display = DISPLAY_INLINE_BLOCK -# elif tagType == TAG_LI: -# result.display = DISPLAY_LIST_ITEM -# else: -# result.display = DISPLAY_NONE -# -# case tagType -# of TAG_CENTER: -# result.centered = true -# of TAG_B: -# result.bold = true -# of TAG_I: -# result.italic = true -# of TAG_U: -# result.underscore = true -# of TAG_HEAD: -# result.hidden = true -# of TAG_STYLE: -# result.hidden = true -# of TAG_SCRIPT: -# result.hidden = true -# of TAG_OPTION: -# result.hidden = true #TODO -# of TAG_PRE, TAG_TD, TAG_TH: -# result.margin = 1 -# of TAG_UL, TAG_OL: -# result.indent = 2 -# result.margin = 1 -# of TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6: -# result.bold = true -# result.margin = 1 -# of TAG_A: -# result.islink = true -# of TAG_INPUT: -# HtmlInputElement(result).size = 20 -# else: discard -# -# if parentNode.isElemNode(): -# let parent = HtmlElement(parentNode) -# result.centered = result.centered or parent.centered -# result.bold = result.bold or parent.bold -# result.italic = result.italic or parent.italic -# result.underscore = result.underscore or parent.underscore -# result.hidden = result.hidden or parent.hidden -# result.islink = result.islink or parent.islink - -func inputSize*(str: string): int = - if str.len == 0: - return 20 - for c in str: - if not c.isDigit: - return 20 - return str.parseInt() - -proc genEntityMap(): RadixTree[string] = - let entity = staticRead"entity.json" - let entityJson = parseJson(entity) - var entityMap = newRadixTree[string]() - - for k, v in entityJson: - entityMap[k.substr(1)] = v{"characters"}.getStr() - - return entityMap - -const entityMap = genEntityMap() - -func genHexCharMap(): seq[int] = - for i in 0..255: - case chr(i) - of '0'..'9': result &= i - ord('0') - of 'a'..'f': result &= i - ord('a') + 10 - of 'A'..'F': result &= i - ord('A') + 10 - else: result &= -1 - -func genDecCharMap(): seq[int] = - for i in 0..255: - case chr(i) - of '0'..'9': result &= i - ord('0') - else: result &= -1 - -const hexCharMap = genHexCharMap() -const decCharMap = genDecCharMap() - -#w3m's getescapecmd and parse_tag, transpiled to nim. -#(C) Copyright 1994-2002 by Akinori Ito -#(C) Copyright 2002-2011 by Akinori Ito, Hironori Sakamoto, Fumitoshi Ukai -# -#Use, modification and redistribution of this software is hereby granted, -#provided that this entire copyright notice is included on any copies of -#this software and applications and derivations thereof. -# -#This software is provided on an "as is" basis, without warranty of any -#kind, either expressed or implied, as to any matter including, but not -#limited to warranty of fitness of purpose, or merchantability, or -#results obtained from use of this software. -proc getescapecmd(buf: string, at: var int): string = - var i = at - - if buf[i] == '#': #num - inc i - var num: int - if buf[i].tolower() == 'x': #hex - inc i - if not isdigit(buf[i]): - at = i - return "" - - num = hexCharMap[int(buf[i])] - inc i - while i < buf.len and hexCharMap[int(buf[i])] != -1: - num *= 0x10 - num += hexCharMap[int(buf[i])] - inc i - else: #dec - if not isDigit(buf[i]): - at = i - return "" - - num = decCharMap[int(buf[i])] - inc i - while i < buf.len and isDigit(buf[i]): - num *= 10 - num += decCharMap[int(buf[i])] - inc i - - if buf[i] == ';': - inc i - at = i - return $(Rune(num)) - elif not isAlphaAscii(buf[i]): - return "" - - var n: uint16 = 0 - var s = "" - while true: - let c = buf[i] - s &= c - if not entityMap.hasPrefix(s, n): - break - let pn = n - n = entityMap.getPrefix(s, n) - if n != pn: - s = "" - inc i - - if entityMap.nodes[n].leaf: - at = i - return entityMap.nodes[n].value - - return "" - -type - DOMParsedTag = object - tagid: TagType - attrs: Table[string, string] - open: bool - -proc parse_tag(buf: string, at: var int): DOMParsedTag = - var tag = DOMParsedTag() - tag.open = true - - #Parse tag name - var tagname = "" - inc at - if buf[at] == '/': - inc at - tag.open = false - skipBlanks(buf, at) - - while at < buf.len and not buf[at].isWhitespace() and not (tag.open and buf[at] == '/') and buf[at] != '>': - tagname &= buf[at].tolower() - at += buf.runeLenAt(at) - - tag.tagid = tagType(tagname) - skipBlanks(buf, at) - - while at < buf.len and buf[at] != '>': - var value = "" - var attrname = "" - while at < buf.len and buf[at] != '=' and not buf[at].isWhitespace() and buf[at] != '>': - attrname &= buf[at].tolower() - at += buf.runeLenAt(at) - - skipBlanks(buf, at) - if buf[at] == '=': - inc at - skipBlanks(buf, at) - if at < buf.len and (buf[at] == '"' or buf[at] == '\''): - let startc = buf[at] - inc at - while at < buf.len and buf[at] != startc: - var r: Rune - fastRuneAt(buf, at, r) - if r == Rune('&'): - value &= getescapecmd(buf, at) - else: - value &= $r - if at < buf.len: - inc at - elif at < buf.len: - while at < buf.len and not buf[at].isWhitespace() and buf[at] != '>': - value &= buf[at] - at += buf.runeLenAt(at) - - if attrname.len > 0: - tag.attrs[attrname] = value - - while at < buf.len and buf[at] != '>': - at += buf.runeLenAt(at) - - if at < buf.len and buf[at] == '>': - inc at - return tag - -proc insertNode(parent: Node, node: Node) = - parent.childNodes.add(node) - - if parent.firstChild == nil: - parent.firstChild = node - - parent.lastChild = node - - if parent.childNodes.len > 1: - let prevSibling = parent.childNodes[^1] - prevSibling.nextSibling = node - node.previousSibling = prevSibling - - node.parentNode = parent - if parent.nodeType == ELEMENT_NODE: - node.parentElement = Element(parent) - - if parent.ownerDocument != nil: - node.ownerDocument = parent.ownerDocument - elif parent.nodeType == DOCUMENT_NODE: - node.ownerDocument = Document(parent) - -proc processDocumentStartNode(state: var ParseState, newNode: Node) = - insertNode(state.parentNode, newNode) - state.parentNode = newNode - -proc processDocumentEndNode(state: var ParseState) = - if state.parentNode == nil or state.parentNode.parentNode == nil: - return - state.parentNode = state.parentNode.parentNode - -proc processDocumentText(state: var ParseState) = - if state.textNode == nil: - state.textNode = newText() - - processDocumentStartNode(state, state.textNode) - processDocumentEndNode(state) - -proc processDocumentStartElement(state: var ParseState, element: Element, tag: DOMParsedTag) = - for k, v in tag.attrs: - element.attributes[k] = element.newAttr(k, v) - - element.id = element.getAttrValue("id") - if element.attributes.hasKey("class"): - for w in unicode.split(element.attributes["class"].value, Rune(' ')): - element.classList.add(w) - - case element.tagType - of TAG_SCRIPT: - state.in_script = true - of TAG_NOSCRIPT: - state.in_noscript = true - of TAG_STYLE: - state.in_style = true - of TAG_SELECT: - HTMLSelectElement(element).name = element.getAttrValue("name") - HTMLSelectElement(element).value = element.getAttrValue("value") - of TAG_INPUT: - HTMLInputElement(element).value = element.getAttrValue("value") - HTMLInputElement(element).itype = element.getAttrValue("type").inputType() - HTMLInputElement(element).size = element.getAttrValue("size").inputSize() - of TAG_A: - HTMLAnchorElement(element).href = element.getAttrValue("href") - of TAG_OPTION: - HTMLOptionElement(element).value = element.getAttrValue("href") - else: discard - - if state.parentNode.nodeType == ELEMENT_NODE: - case element.tagType - of TAG_LI, TAG_P: - if Element(state.parentNode).tagType == element.tagType: - processDocumentEndNode(state) - of TAG_H1: - HTMLHeadingElement(element).rank = 1 - of TAG_H2: - HTMLHeadingElement(element).rank = 2 - of TAG_H3: - HTMLHeadingElement(element).rank = 3 - of TAG_H4: - HTMLHeadingElement(element).rank = 4 - of TAG_H5: - HTMLHeadingElement(element).rank = 5 - of TAG_H6: - HTMLHeadingElement(element).rank = 6 - else: discard - - processDocumentStartNode(state, element) - - if element.tagType in VoidTagTypes: - processDocumentEndNode(state) - -proc processDocumentEndElement(state: var ParseState, tag: DOMParsedTag) = - if tag.tagid in VoidTagTypes: - return - if state.parentNode.nodeType == ELEMENT_NODE: - if Element(state.parentNode).tagType in {TAG_LI, TAG_P}: - processDocumentEndNode(state) - - processDocumentEndNode(state) - -proc processDocumentTag(state: var ParseState, tag: DOMParsedTag) = - if state.in_script: - if tag.tagid == TAG_SCRIPT: - state.in_script = false - else: - return - - if state.in_style: - if tag.tagid == TAG_STYLE: - state.in_style = false - else: - return - - if state.in_noscript: - if tag.tagid == TAG_NOSCRIPT: - state.in_noscript = false - else: - return - - if tag.open: - processDocumentStartElement(state, newHtmlElement(tag.tagid), tag) - else: - processDocumentEndElement(state, tag) - #XXX PROCDOCCASE stuff... good lord I'll never finish this thing - -proc processDocumentPart(state: var ParseState, buf: string) = - var at = 0 - var max = 0 - var was_script = false - - max = buf.len - - while at < max: - case buf[at] - of '&': - inc at - let p = getescapecmd(buf, at) - if state.in_comment: - CharacterData(state.parentNode).data &= p - else: - processDocumentText(state) - state.textNode.data &= p - of '<': - if state.in_comment: - CharacterData(state.parentNode).data &= buf[at] - inc at - else: - var p = at - inc p - if p < max and buf[p] == '!': - inc p - if p < max and buf[p] == '-': - inc p - if p < max and buf[p] == '-': - inc p - at = p - state.in_comment = true - processDocumentStartNode(state, newComment()) - if state.textNode != nil: - state.textNode.rawtext = state.textNode.getRawText() - state.textNode = nil - - if not state.in_comment: - if state.textNode != nil: - state.textNode.rawtext = state.textNode.getRawText() - state.textNode = nil - p = at - var tag = parse_tag(buf, at) - was_script = state.in_script - - processDocumentTag(state, tag) -# if (was_script) { -# if (state->in_script) { -# ptr = p; -# processDocumentText(&state->parentNode, &state->textNode); -# Strcat_char(((CharacterData *)state->textNode)->data, *ptr++); -# } else if (buffer->javascript_enabled) { -# loadJSToBuffer(buffer, childTextContentNode(state->parentNode->lastChild)->ptr, "", state->document); -# } -# } - elif buf[at] == '-' and state.in_comment: - var p = at - inc p - if p < max and buf[p] == '-': - inc p - if p < max and buf[p] == '>': - inc p - at = p - state.in_comment = false - processDocumentEndNode(state) - - if state.in_comment: - CharacterData(state.parentNode).data &= buf[at] - inc at - else: - var r: Rune - fastRuneAt(buf, at, r) - if state.in_comment: - CharacterData(state.parentNode).data &= $r - else: - processDocumentText(state) - state.textNode.data &= $r - -proc parseHtml*(inputStream: Stream): Document = - let document = newDocument() - - var state = ParseState(stream: inputStream) - state.parentNode = document - - var till_when = false - - var buf = "" - var lineBuf: string - while not inputStream.atEnd(): - lineBuf = inputStream.readLine() - if lineBuf.len == 0: - break - buf &= lineBuf - - var at = 0 - while at < lineBuf.len: - case lineBuf[at] - of '<': - till_when = true - of '>': - till_when = false - else: discard - at += lineBuf.runeLenAt(at) - - if till_when: - continue - - processDocumentPart(state, buf) - buf = "" - - inputStream.close() - return document diff --git a/radixtree.nim b/radixtree.nim deleted file mode 100644 index 7933f7a3..00000000 --- a/radixtree.nim +++ /dev/null @@ -1,153 +0,0 @@ -import tables -import strutils -import json - -type - RadixNode[T] = object - children*: Table[string, uint16] - case leaf*: bool - of true: value*: T - of false: discard - - RadixTree*[T] = object - nodes*: seq[RadixNode[T]] - -func newRadixTree*[T](): RadixTree[T] = - result.nodes.add(RadixNode[T](leaf: false)) - -proc `[]=`*[T](tree: var RadixTree[T], key: string, value: T) = - var n: uint16 = 0 - var p: uint16 = 0 - var i = 0 - var j = 0 - var s = "" - var t = "" - var nodeKey = "" - # find last matching node - while i < key.len: - s &= key[i] - if s in tree.nodes[n].children: - p = n - n = tree.nodes[n].children[s] - t &= s - j += s.len - nodeKey = s - s = "" - inc i - - for k in tree.nodes[n].children.keys: - if s.len > 0 and k.startsWith(s[0]): - p = n - n = tree.nodes[n].children[k] - t &= k - nodeKey = k - break - - # if first node, just add normally - if n == 0: - tree.nodes.add(RadixNode[T](leaf: true, value: value)) - tree.nodes[n].children[key] = uint16(tree.nodes.len - 1) - else: - i = 0 - var conflict = false - # compare new key with the one we found so far - while i < t.len and i < key.len: - if key[i] == t[i]: - inc i - else: - conflict = true - break - - if conflict: - # conflict somewhere, so: - # * add new non-leaf to parent - # * add old to non-leaf - # * add new to non-leaf - # * remove old from parent - assert(i != 0) - - tree.nodes[p].children[key.substr(j, i - 1)] = uint16(tree.nodes.len) - tree.nodes.add(RadixNode[T](leaf: false)) - tree.nodes[^1].children[t.substr(i)] = n - tree.nodes[^1].children[key.substr(i)] = uint16(tree.nodes.len) - tree.nodes.add(RadixNode[T](leaf: true, value: value)) - tree.nodes[p].children.del(nodeKey) - else: # new is either substr of old or old is substr of new - # new matches a node, so replace - if key.len == t.len: - let children = tree.nodes[n].children - tree.nodes[n] = RadixNode[T](leaf: true, value: value) - tree.nodes[n].children = children - elif i == j: - # new is longer than the old, so add child to old - tree.nodes[n].children[key.substr(i)] = uint16(tree.nodes.len) - tree.nodes.add(RadixNode[T](leaf: true, value: value)) - elif i > 0: - # new is shorter than old, so: - # * add new to parent - # * add old to new - # * remove old from parent - tree.nodes[p].children[key.substr(j, i - 1)] = uint16(tree.nodes.len) - tree.nodes.add(RadixNode[T](leaf: true, value: value)) - tree.nodes[^1].children[t.substr(i)] = n - tree.nodes[p].children.del(nodeKey) - -func getPrefix*[T](tree: RadixTree[T], prefix: string, at: uint16 = 0): uint16 = - var s = "" - var t = "" - var n = at - var i = 0 - while t.len < prefix.len: - s &= prefix[i] - t &= prefix[i] - if s in tree.nodes[n].children: - n = tree.nodes[n].children[s] - s = "" - inc i - - return n - -func hasPrefix*[T](tree: RadixTree[T], prefix: string, at: uint16 = 0): bool = - var s = "" - var t = "" - var n = at - var i = 0 - while i < prefix.len: - s &= prefix[i] - if s in tree.nodes[n].children: - n = tree.nodes[n].children[s] - t &= s - s = "" - inc i - - if t.len == prefix.len: - return true - - for k in tree.nodes[n].children.keys: - if k.startsWith(prefix.substr(t.len)): - return true - - return false - -#tests -#var tree = newRadixTree[string]() -#tree.insert("hb", "abc") -#tree.insert("hi", "second") -#tree.insert("hia", "second") -#tree.insert("hia", "third") -#tree.insert("hiahhhooo", "two point fifth") -#tree.insert("hiahhho", "two point sixth") -#assert(tree.hasPrefix("h")) -#assert(tree.hasPrefix("hi")) -#assert(not tree.hasPrefix("hio")) -#assert(tree.hasPrefix("hiah")) -#assert(tree.hasPrefix("hiahhho")) -#assert(tree.hasPrefix("hiahhhooo")) -#assert(tree.lookup("hi", "error") != "error") -#assert(tree.lookup("hb", "error") != "error") -#assert(tree.lookup("hio", "error") == "error") -#assert(tree.lookup("hia", "error") != "error") -#assert(tree.lookup("hiahhhooo", "error") != "error") -#assert(tree.lookup("hiahhho", "error") != "error") -#assert(tree.lookup("hiahhhoo", "error") == "error") -#assert(tree.lookup("h", "error") == "error") diff --git a/readme.md b/readme.md index 32c6a7dc..7c95e958 100644 --- a/readme.md +++ b/readme.md @@ -16,7 +16,8 @@ Currently implemented features are: Planned features (roughly in order of importance): -* improved html rendering and parsing +* stylesheets +* improved html rendering (like, actually functioning) * form * table * cookie @@ -25,11 +26,11 @@ Planned features (roughly in order of importance): * image (sixel/kitty) * audio * JavaScript -* extension API (adblock support?) * video (sixel/kitty) -* custom charsets? +* extension API? +* non-unicode charsets? * async? -* markdown? (with pandoc or built-in parser?) +* markdown? (with built-in parser) * gopher? * gemini? diff --git a/src/a.nim b/src/a.nim new file mode 100644 index 00000000..da4e4903 --- /dev/null +++ b/src/a.nim @@ -0,0 +1 @@ +echo int(high(char)) diff --git a/src/buffer.nim b/src/buffer.nim new file mode 100644 index 00000000..5eaa4717 --- /dev/null +++ b/src/buffer.nim @@ -0,0 +1,458 @@ +import options +import uri +import tables +import strutils +import unicode + +import termattrs +import dom +import twtio +import enums +import twtstr + +type + Buffer* = ref BufferObj + BufferObj = object + fmttext*: seq[string] + rawtext*: seq[string] + title*: string + hovertext*: string + width*: int + height*: int + cursorx*: int + cursory*: int + xend*: int + fromx*: int + fromy*: int + nodes*: seq[Node] + links*: seq[Node] + clickables*: seq[Node] + elements*: seq[Element] + idelements*: Table[string, Element] + selectedlink*: Node + printwrite*: bool + attrs*: TermAttributes + document*: Document + +proc newBuffer*(attrs: TermAttributes): Buffer = + return Buffer(width: attrs.termWidth, + height: attrs.termHeight, + attrs: attrs) + +func lastLine*(buffer: Buffer): int = + assert(buffer.fmttext.len == buffer.rawtext.len) + return buffer.fmttext.len - 1 + +func lastVisibleLine*(buffer: Buffer): int = + return min(buffer.fromy + buffer.height - 1, buffer.lastLine()) + +func currentLineLength*(buffer: Buffer): int = + return buffer.rawtext[buffer.cursory].width() + +func atPercentOf*(buffer: Buffer): int = + if buffer.fmttext.len == 0: return 100 + return (100 * (buffer.cursory + 1)) div (buffer.lastLine() + 1) + +func fmtBetween*(buffer: Buffer, sx: int, sy: int, ex: int, ey: int): string = + if sy < ey: + result &= buffer.rawtext[sy].runeSubstr(sx) + var i = sy + 1 + while i < ey - 1: + result &= buffer.rawtext[i] + inc i + result &= buffer.rawtext[i].runeSubstr(0, ex - sx) + else: + result &= buffer.rawtext[sy].runeSubstr(sx, ex - sx) + +func visibleText*(buffer: Buffer): string = + return buffer.fmttext[buffer.fromy..buffer.lastVisibleLine()].join("\n") + +func lastNode*(buffer: Buffer): Node = + return buffer.nodes[^1] + +func cursorOnNode*(buffer: Buffer, node: Node): bool = + if node.y == node.ey and node.y == buffer.cursory: + return buffer.cursorx >= node.x and buffer.cursorx < node.ex + else: + return (buffer.cursory == node.y and buffer.cursorx >= node.x) or + (buffer.cursory > node.y and buffer.cursory < node.ey) or + (buffer.cursory == node.ey and buffer.cursorx < node.ex) + +func findSelectedElement*(buffer: Buffer): Option[HtmlElement] = + if buffer.selectedlink != nil and buffer.selectedLink.parentNode of HtmlElement: + return some(HtmlElement(buffer.selectedlink.parentNode)) + for node in buffer.nodes: + if node.isElemNode(): + if node.getFmtLen() > 0: + if buffer.cursorOnNode(node): return some(HtmlElement(node)) + return none(HtmlElement) + +func canScroll*(buffer: Buffer): bool = + return buffer.lastLine() > buffer.height + +func getElementById*(buffer: Buffer, id: string): Element = + if buffer.idelements.hasKey(id): + return buffer.idelements[id] + return nil + +proc findSelectedNode*(buffer: Buffer): Option[Node] = + for node in buffer.nodes: + if node.getFmtLen() > 0 and node.displayed(): + if buffer.cursory >= node.y and buffer.cursory <= node.y + node.height and buffer.cursorx >= node.x and buffer.cursorx <= node.x + node.width: + return some(node) + return none(Node) + +proc addNode*(buffer: Buffer, node: Node) = + buffer.nodes.add(node) + + if node.isTextNode() and node.parentElement != nil and node.parentElement.getStyle().islink: + buffer.links.add(node) + + if node.isElemNode(): + case Element(node).tagType + of TAG_INPUT, TAG_OPTION: + if not Element(node).hidden: + buffer.clickables.add(node) + else: discard + elif node.isTextNode(): + if node.parentElement != nil and node.parentElement.style.islink: + let anchor = node.ancestor(TAG_A) + assert(anchor != nil) + buffer.clickables.add(anchor) + + if node.isElemNode(): + let elem = Element(node) + buffer.elements.add(elem) + if elem.id != "" and not buffer.idelements.hasKey(elem.id): + buffer.idelements[elem.id] = elem + +proc writefmt*(buffer: Buffer, str: string) = + buffer.fmttext &= str + if buffer.printwrite: + stdout.write(str) + +proc writefmt*(buffer: Buffer, c: char) = + buffer.rawtext &= $c + if buffer.printwrite: + stdout.write(c) + +proc writeraw*(buffer: Buffer, str: string) = + buffer.rawtext &= str + +proc writeraw*(buffer: Buffer, c: char) = + buffer.rawtext &= $c + +proc write*(buffer: Buffer, str: string) = + buffer.writefmt(str) + buffer.writeraw(str) + +proc write*(buffer: Buffer, c: char) = + buffer.writefmt(c) + buffer.writeraw(c) + +proc clearText*(buffer: Buffer) = + buffer.fmttext.setLen(0) + buffer.rawtext.setLen(0) + +proc clearNodes*(buffer: Buffer) = + buffer.nodes.setLen(0) + buffer.links.setLen(0) + buffer.clickables.setLen(0) + buffer.elements.setLen(0) + buffer.idelements.clear() + +proc clearBuffer*(buffer: Buffer) = + buffer.clearText() + buffer.clearNodes() + buffer.cursorx = 0 + buffer.cursory = 0 + buffer.fromx = 0 + buffer.fromy = 0 + buffer.hovertext = "" + buffer.selectedlink = nil + +proc scrollTo*(buffer: Buffer, y: int): bool = + if y == buffer.fromy: + return false + buffer.fromy = min(max(buffer.lastLine() - buffer.height + 1, 0), y) + buffer.cursory = min(max(buffer.fromy, buffer.cursory), buffer.fromy + buffer.height) + return true + +proc cursorTo*(buffer: Buffer, x: int, y: int): bool = + result = false + buffer.cursory = min(max(y, 0), buffer.lastLine()) + if buffer.fromy > buffer.cursory: + buffer.fromy = max(buffer.cursory, 0) + result = true + elif buffer.fromy + buffer.height - 1 <= buffer.cursory: + buffer.fromy = max(buffer.cursory - buffer.height + 2, 0) + result = true + buffer.cursorx = min(max(x, 0), buffer.currentLineLength()) + #buffer.fromX = min(max(buffer.currentLineLength() - buffer.width + 1, 0), 0) #TODO + +proc cursorDown*(buffer: Buffer): bool = + if buffer.cursory < buffer.lastLine(): + inc buffer.cursory + if buffer.cursorx >= buffer.currentLineLength(): + buffer.cursorx = max(buffer.currentLineLength() - 1, 0) + elif buffer.xend > 0: + buffer.cursorx = min(buffer.currentLineLength() - 1, buffer.xend) + if buffer.cursory >= buffer.lastVisibleLine() and buffer.lastVisibleLine() != buffer.lastLine(): + inc buffer.fromy + return true + return false + +proc cursorUp*(buffer: Buffer): bool = + if buffer.cursory > 0: + dec buffer.cursory + if buffer.cursorx > buffer.currentLineLength(): + if buffer.cursorx == 0: + buffer.xend = buffer.cursorx + buffer.cursorx = max(buffer.currentLineLength() - 1, 0) + elif buffer.xend > 0: + buffer.cursorx = min(buffer.currentLineLength() - 1, buffer.xend) + if buffer.cursory < buffer.fromy: + dec buffer.fromy + return true + return false + +proc cursorRight*(buffer: Buffer): bool = + if buffer.cursorx < buffer.currentLineLength() - 1: + inc buffer.cursorx + buffer.xend = 0 + else: + buffer.xend = buffer.cursorx + return false + +proc cursorLeft*(buffer: Buffer): bool = + if buffer.cursorx > 0: + dec buffer.cursorx + buffer.xend = 0 + return false + +proc cursorLineBegin*(buffer: Buffer) = + buffer.cursorx = 0 + buffer.xend = 0 + +proc cursorLineEnd*(buffer: Buffer) = + buffer.cursorx = buffer.currentLineLength() - 1 + buffer.xend = buffer.cursorx + +iterator revnodes*(buffer: Buffer): Node {.inline.} = + var i = buffer.nodes.len - 1 + while i >= 0: + yield buffer.nodes[i] + dec i + +proc cursorNextWord*(buffer: Buffer): bool = + let llen = buffer.currentLineLength() - 1 + var r: Rune + var x = buffer.cursorx + var y = buffer.cursory + if llen >= 0: + fastRuneAt(buffer.rawtext[y], x, r, false) + + while r != Rune(' '): + if x >= llen: + break + inc x + fastRuneAt(buffer.rawtext[y], x, r, false) + + while r == Rune(' '): + if x >= llen: + break + inc x + fastRuneAt(buffer.rawtext[y], x, r, false) + + if x >= llen: + if y < buffer.lastLine(): + inc y + x = 0 + return buffer.cursorTo(x, y) + +proc cursorPrevWord*(buffer: Buffer): bool = + var r: Rune + var x = buffer.cursorx + var y = buffer.cursory + if buffer.currentLineLength() > 0: + fastRuneAt(buffer.rawtext[y], x, r, false) + + while r != Rune(' '): + if x == 0: + break + dec x + fastRuneAt(buffer.rawtext[y], x, r, false) + + while r == Rune(' '): + if x == 0: + break + dec x + fastRuneAt(buffer.rawtext[y], x, r, false) + + if x == 0: + if y > 0: + dec y + x = buffer.rawtext[y].runeLen() - 1 + return buffer.cursorTo(x, y) + +iterator revclickables*(buffer: Buffer): Node {.inline.} = + var i = buffer.clickables.len - 1 + while i >= 0: + yield buffer.clickables[i] + dec i + +proc cursorNextLink*(buffer: Buffer): bool = + for node in buffer.clickables: + if node.y > buffer.cursory or (node.y == buffer.cursorY and node.x > buffer.cursorx): + result = buffer.cursorTo(node.x, node.y) + if buffer.cursorx < buffer.currentLineLength(): + var r: Rune + fastRuneAt(buffer.rawtext[buffer.cursory], buffer.cursorx, r, false) + if r == Rune(' '): + return result or buffer.cursorNextWord() + return result + return false + +proc cursorPrevLink*(buffer: Buffer): bool = + for node in buffer.revclickables: + if node.y < buffer.cursorY or (node.y == buffer.cursorY and node.x < buffer.cursorx): + return buffer.cursorTo(node.x, node.y) + return false + +proc cursorFirstLine*(buffer: Buffer): bool = + if buffer.fromy > 0: + buffer.fromy = 0 + result = true + else: + result = false + + buffer.cursorY = 0 + buffer.cursorLineBegin() + +proc cursorLastLine*(buffer: Buffer): bool = + if buffer.fromy < buffer.lastLine() - buffer.height: + buffer.fromy = buffer.lastLine() - (buffer.height - 2) + result = true + else: + result = false + buffer.cursory = buffer.lastLine() + buffer.cursorLineBegin() + +proc cursorTop*(buffer: Buffer): bool = + buffer.cursorY = buffer.fromy + return false + +proc cursorMiddle*(buffer: Buffer): bool = + buffer.cursorY = min(buffer.fromy + (buffer.height - 2) div 2, buffer.lastLine()) + return false + +proc cursorBottom*(buffer: Buffer): bool = + buffer.cursorY = min(buffer.fromy + buffer.height - 2, buffer.lastLine()) + return false + +proc centerLine*(buffer: Buffer): bool = + let ny = max(min(buffer.cursory - buffer.height div 2, buffer.lastLine() - buffer.height + 2), 0) + if ny != buffer.fromy: + buffer.fromy = ny + return true + return false + +proc halfPageUp*(buffer: Buffer): bool = + buffer.cursory = max(buffer.cursorY - buffer.height div 2 + 1, 0) + let nfy = max(0, buffer.fromy - buffer.height div 2 + 1) + if nfy != buffer.fromy: + buffer.fromy = nfy + return true + return false + +proc halfPageDown*(buffer: Buffer): bool = + buffer.cursory = min(buffer.cursorY + buffer.height div 2 - 1, buffer.lastLine()) + let nfy = min(max(buffer.lastLine() - buffer.height + 2, 0), buffer.fromy + buffer.height div 2 - 1) + if nfy != buffer.fromy: + buffer.fromy = nfy + return true + return false + +proc pageUp*(buffer: Buffer): bool = + buffer.cursorY = max(buffer.cursorY - buffer.height + 1, 1) + buffer.fromy = max(0, buffer.fromy - buffer.height) + return true + +proc pageDown*(buffer: Buffer): bool = + buffer.cursorY = min(buffer.cursorY + buffer.height div 2 - 1, buffer.lastLine()) + buffer.fromy = min(max(buffer.lastLine() - buffer.height + 1, 0), buffer.fromy + buffer.height div 2) + return true + +proc scrollDown*(buffer: Buffer): bool = + if buffer.fromy + buffer.height - 1 <= buffer.lastLine(): + inc buffer.fromy + if buffer.fromy >= buffer.cursory: + discard buffer.cursorDown() + return true + discard buffer.cursorDown() + return false + +proc scrollUp*(buffer: Buffer): bool = + if buffer.fromy > 0: + dec buffer.fromy + if buffer.fromy + buffer.height - 1 <= buffer.cursorY: + discard buffer.cursorUp() + return true + discard buffer.cursorUp() + return false + +proc checkLinkSelection*(buffer: Buffer): bool = + if buffer.selectedlink != nil: + if buffer.cursorOnNode(buffer.selectedlink): + return false + else: + let anchor = buffer.selectedlink.ancestor(TAG_A) + anchor.style.selected = false + buffer.selectedlink.fmttext = buffer.selectedlink.getFmtText() + buffer.selectedlink = nil + buffer.hovertext = "" + var stack: seq[Node] + stack.add(anchor) + while stack.len > 0: + let elem = stack.pop() + elem.fmttext = elem.getFmtText() + for child in elem.childNodes: + stack.add(child) + for node in buffer.links: + if buffer.cursorOnNode(node): + buffer.selectedlink = node + let anchor = node.ancestor(TAG_A) + assert(anchor != nil) + anchor.style.selected = true + buffer.hovertext = HtmlAnchorElement(anchor).href + var stack: seq[Node] + stack.add(anchor) + while stack.len > 0: + let elem = stack.pop() + elem.fmttext = elem.getFmtText() + for child in elem.childNodes: + stack.add(child) + return true + return false + +proc gotoAnchor*(buffer: Buffer): bool = + if buffer.document.location.anchor != "": + let node = buffer.getElementById(buffer.document.location.anchor) + if node != nil: + return buffer.scrollTo(max(node.y - buffer.height div 2, 0)) + return false + +proc setLocation*(buffer: Buffer, uri: Uri) = + buffer.document.location = uri + +proc gotoLocation*(buffer: Buffer, uri: Uri) = + buffer.document.location = buffer.document.location.combine(uri) + +proc refreshTermAttrs*(buffer: Buffer): bool = + let newAttrs = getTermAttributes() + if newAttrs != buffer.attrs: + buffer.attrs = newAttrs + buffer.width = newAttrs.termWidth + buffer.height = newAttrs.termHeight + return true + return false diff --git a/src/config b/src/config new file mode 100644 index 00000000..99397288 --- /dev/null +++ b/src/config @@ -0,0 +1,399 @@ +#normal mode keybindings +nmap q QUIT +nmap h CURSOR_LEFT +nmap j CURSOR_DOWN +nmap k CURSOR_UP +nmap l CURSOR_RIGHT +nmap \e[D CURSOR_LEFT +nmap \e[B CURSOR_DOWN +nmap \e[A CURSOR_UP +nmap \e[C CURSOR_RIGHT +nmap ^ CURSOR_LINEBEGIN +nmap $ CURSOR_LINEEND +nmap b CURSOR_PREV_WORD +nmap w CURSOR_NEXT_WORD +nmap [ CURSOR_PREV_LINK +nmap ] CURSOR_NEXT_LINK +nmap H CURSOR_TOP +nmap M CURSOR_MIDDLE +nmap L CURSOR_BOTTOM +nmap C-d HALF_PAGE_DOWN +nmap C-u HALF_PAGE_UP +nmap C-f PAGE_DOWN +nmap C-b PAGE_UP +nmap \e[6~ PAGE_DOWN +nmap \e[5~ PAGE_UP +nmap C-e SCROLL_DOWN +nmap C-y SCROLL_UP +nmap J SCROLL_DOWN +nmap K SCROLL_UP +nmap C-m CLICK +nmap C-j CLICK +nmap C-l CHANGE_LOCATION +nmap U RELOAD +nmap r RESHAPE +nmap R REDRAW +nmap gg CURSOR_FIRST_LINE +nmap G CURSOR_LAST_LINE +nmap \e[H CURSOR_FIRST_LINE +nmap \e[F CURSOR_LAST_LINE +nmap z CENTER_LINE +nmap C-g LINE_INFO + +#line editing keybindings +lemap C-m LINED_SUBMIT +lemap C-j LINED_SUBMIT +lemap C-h LINED_BACKSPACE +lemap C-? LINED_BACKSPACE +lemap C-d LINED_DELETE +lemap C-c LINED_CANCEL +lemap \eb LINED_PREV_WORD +lemap \ef LINED_NEXT_WORD +lemap C-b LINED_BACK +lemap C-f LINED_FORWARD +lemap C-u LINED_CLEAR +lemap C-k LINED_KILL +lemap C-w LINED_KILL_WORD +lemap C-v LINED_ESC +lemap C-g LINED_COMPOSE_TOGGLE + +#compose keybindings + +#european +comp a: ä +comp o: ö +comp u: ü +comp u" ű +comp o" ő + +comp a' á +comp e' é +comp i' í +comp o' ó +comp u' ú + +comp sS ß +comp n~ ñ + +#hiragana +comp a あ +comp i い +comp u う +comp e え +comp o お + +comp la ぁ +comp li ぃ +comp lu ぅ +comp le ぇ +comp lo ぉ + +comp ka か +comp ki き +comp ku く +comp ke け +comp ko こ + +comp kka っか +comp kki っき +comp kku っく +comp kke っけ +comp kko っこ + +comp sa さ +comp shi し +comp su す +comp se せ +comp so そ + +comp ssa っさ +comp sshi っし +comp ssu っす +comp sse っせ +comp sso っそ + +comp ta た +comp chi ち +comp tsu つ +comp te て +comp to と + +comp tta った +comp tchi っち +comp ttsu っつ +comp tte って +comp tto っと + +comp na な +comp ni に +comp nu ぬ +comp ne ね +comp no の + +comp ha は +comp hi ひ +comp fu ふ +comp he へ +comp ho ほ + +comp ma ま +comp mi み +comp mu む +comp me め +comp mo も + +comp ya や +comp yu ゆ +comp yo よ + +comp ra ら +comp ri り +comp ru る +comp re れ +comp ro ろ + +comp wa わ +comp wi ゐ +comp we ゑ +comp wo を + +comp ga が +comp gi ぎ +comp gu ぐ +comp ge げ +comp go ご + +comp za ざ +comp ji じ +comp zu ず +comp ze ぜ +comp zo ぞ + +comp da だ +comp dji ぢ +comp dzu づ +comp de で +comp do ど + +comp ba ば +comp bi び +comp bu ぶ +comp be べ +comp bo ぼ + +comp pa ぱ +comp pi ぴ +comp pu ぷ +comp pe ぺ +comp po ぽ + +comp n ん + +comp kya きゃ +comp kyu きゅ +comp kyo きょ + +comp sha しゃ +comp shu しゅ +comp sho しょ + +comp cha ちゃ +comp chu ちゅ +comp cho ちょ + +comp nya にゃ +comp nyu にゅ +comp nyo にょ + +comp hya ひゃ +comp hyu ひゅ +comp hyo ひょ + +comp mya みゃ +comp myu みゅ +comp myo みょ + +comp rya りゃ +comp ryu りゅ +comp ryo りょ + +comp gya ぎゃ +comp gyu ぎゅ +comp gyo ぎょ + +comp ja じゃ +comp ju じゅ +comp jo じょ + +comp bya びゃ +comp byu びゅ +comp byo びょ + +comp pya ぴゃ +comp pyu ぴゅ +comp pyo ぴょ + +comp kwa くゎ +comp gwa ぐゎ + +#katakana +comp A ア +comp I イ +comp U ウ +comp E エ +comp O オ + +comp LA ォ +comp LI ィ +comp LU ゥ +comp LE ェ +comp LO ォ + +comp KA か +comp KI き +comp KU く +comp KE け +comp KO こ + +comp KKA ッカ +comp KKI ッキ +comp KKU ック +comp KKE ッケ +comp KKO ッコ + +comp SA サ +comp SHI シ +comp SU ス +comp SE セ +comp SO ソ + +comp SSA ッサ +comp SSHI ッシ +comp SSU ッス +comp SSE ッセ +comp SSO ッソ + +comp TA タ +comp CHI チ +comp TSU ツ +comp TE テ +comp TO ト + +comp TTA ッタ +comp TCHI ッチ +comp TTSU ッツ +comp TTE ッテ +comp TTO ッと + +comp NA ナ +comp NI ニ +comp NU ヌ +comp NE ネ +comp NO ノ + +comp HA ハ +comp HI ヒ +comp FU フ +comp HE ヘ +comp HO ホ + +comp MA マ +comp MI ミ +comp MU ム +comp ME メ +comp MO モ + +comp YA ヤ +comp YU ユ +comp YO ヨ + +comp RA ラ +comp RI リ +comp RU ル +comp RE レ +comp RO ロ + +comp WA ワ +comp WI ヰ +comp WE ヱ +comp WO ヲ + +comp GA ガ +comp GI ギ +comp GU グ +comp GE ゲ +comp GO ゴ + +comp ZA ザ +comp JI ジ +comp ZU ズ +comp ZE ゼ +comp ZO ゾ + +comp DA ダ +comp DJI ヂ +comp DZU ヅ +comp DE デ +comp DO ド + +comp BA バ +comp BI ビ +comp BU ブ +comp BE ベ +comp BO ボ + +comp PA パ +comp PI ピ +comp PU プ +comp PE ペ +comp PO ポ + +comp N ン +comp xc ー + +comp KYA キャ +comp KYU キュ +comp KYO キョ + +comp SHA シャ +comp SHU シュ +comp SHO ショ + +comp CHA チャ +comp CHU チュ +comp CHO チョ + +comp NYA ニャ +comp NYU ニュ +comp NYO ニョ + +comp HYA ヒャ +comp HYU ヒュ +comp HYO ヒョ + +comp MYA ミャ +comp MYU ミュ +comp MYO ミョ + +comp RYA リャ +comp RYU リュ +comp RYO リョ + +comp GYA ギャ +comp GYU ギュ +comp GYO ギョ + +comp JA ジャ +comp JU ジュ +comp JO ジョ + +comp BYA ビャ +comp BYU ビュ +comp BYO ビョ + +comp PYA ピャ +comp PYU ピュ +comp PYO ピョ + +comp KWA クヮ +comp GWA グヮ diff --git a/src/config.nim b/src/config.nim new file mode 100644 index 00000000..6d185a1d --- /dev/null +++ b/src/config.nim @@ -0,0 +1,139 @@ +import tables +import strutils + +import twtstr +import radixtree + +type + TwtAction* = + enum + NO_ACTION, + ACTION_FEED_NEXT, + ACTION_QUIT, + ACTION_CURSOR_UP, ACTION_CURSOR_DOWN, ACTION_CURSOR_LEFT, ACTION_CURSOR_RIGHT, + ACTION_CURSOR_LINEEND, ACTION_CURSOR_LINEBEGIN, + ACTION_CURSOR_NEXT_WORD, ACTION_CURSOR_PREV_WORD, + ACTION_CURSOR_NEXT_NODE, ACTION_CURSOR_PREV_NODE, + ACTION_CURSOR_NEXT_LINK, ACTION_CURSOR_PREV_LINK, + ACTION_PAGE_DOWN, ACTION_PAGE_UP, + ACTION_HALF_PAGE_DOWN, ACTION_HALF_PAGE_UP, + ACTION_SCROLL_DOWN, ACTION_SCROLL_UP, + ACTION_CLICK, + ACTION_CHANGE_LOCATION, + ACTION_RELOAD, ACTION_RESHAPE, ACTION_REDRAW, + ACTION_CURSOR_FIRST_LINE, ACTION_CURSOR_LAST_LINE, + ACTION_CURSOR_TOP, ACTION_CURSOR_MIDDLE, ACTION_CURSOR_BOTTOM, + ACTION_CENTER_LINE, ACTION_LINE_INFO, + ACTION_LINED_SUBMIT, ACTION_LINED_CANCEL, + ACTION_LINED_BACKSPACE, ACTION_LINED_DELETE, + ACTION_LINED_CLEAR, ACTION_LINED_KILL, ACTION_LINED_KILL_WORD, + ACTION_LINED_BACK, ACTION_LINED_FORWARD, + ACTION_LINED_PREV_WORD, ACTION_LINED_NEXT_WORD, + ACTION_LINED_COMPOSE_TOGGLE, ACTION_LINED_COMPOSE_ON, ACTION_LINED_COMPOSE_OFF + ACTION_LINED_ESC + + ActionMap = Table[string, TwtAction] + ComposeMap = RadixTree[string] + +var normalActionRemap*: ActionMap +var linedActionRemap*: ActionMap +var composeRemap*: ComposeMap + +func getRealKey(key: string): string = + var realk: string + var currchar: char + var control = 0 + var skip = false + for c in key: + if c == '\\': + skip = true + elif skip: + if c == 'e': + realk &= '\e' + else: + realk &= c + skip = false + elif c == 'C': + inc control + currchar = c + elif c == '-' and control == 1: + inc control + elif control == 1: + realk &= 'C' & c + control = 0 + elif control == 2: + realk &= getControlChar(c) + control = 0 + else: + realk &= c + if control == 1: + realk &= 'C' + return realk + +func constructActionTable*(origTable: ActionMap): ActionMap = + var newTable: ActionMap + var strs: seq[string] + for k in origTable.keys: + let realk = getRealKey(k) + var teststr = "" + for c in realk: + teststr &= c + strs.add(teststr) + + for k, v in origTable: + let realk = getRealKey(k) + var teststr = "" + for c in realk: + teststr &= c + if strs.contains(teststr): + newTable[teststr] = ACTION_FEED_NEXT + newTable[realk] = v + return newTable + +proc parseConfigLine(line: string, nmap: var ActionMap, lemap: var ActionMap, + compose: var ComposeMap) = + if line.len == 0 or line[0] == '#': + return + let cmd = line.split(' ') + if cmd.len == 3: + if cmd[0] == "nmap": + nmap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) + elif cmd[0] == "lemap": + lemap[getRealKey(cmd[1])] = parseEnum[TwtAction]("ACTION_" & cmd[2]) + elif cmd[0] == "comp": + compose[getRealKey(cmd[1])] = cmd[2] + +proc staticReadKeymap(): (ActionMap, ActionMap, ComposeMap) = + let config = staticRead"config" + var nmap: ActionMap + var lemap: ActionMap + var compose = newRadixTree[string]() + for line in config.split('\n'): + parseConfigLine(line, nmap, lemap, compose) + + nmap = constructActionTable(nmap) + lemap = constructActionTable(lemap) + return (nmap, lemap, compose) + +const (normalActionMap, linedActionMap, composeMap) = staticReadKeymap() + +normalActionRemap = normalActionMap +linedActionRemap = linedActionMap +composeRemap = composeMap + +proc readConfig*(filename: string): bool = + var f: File + let status = f.open(filename, fmRead) + var nmap: ActionMap + var lemap: ActionMap + var compose = newRadixTree[string]() + if status: + var line: TaintedString + while f.readLine(line): + parseConfigLine(line, nmap, lemap, compose) + + normalActionRemap = constructActionTable(normalActionMap) + linedActionRemap = constructActionTable(linedActionMap) + return true + else: + return false diff --git a/src/default.css b/src/default.css new file mode 100644 index 00000000..db11f036 --- /dev/null +++ b/src/default.css @@ -0,0 +1,20 @@ +head { + display: none +} + +a, abbr, b, bdo, br, button, cite, code, +del, dfn, em, font, i, img, ins, input, +iframe, kbd, label, map, object, q, samp, +script, select, small, span, strong, sub, sup, +textarea, tt, var, font, iframe, u, s, strike, +frame, img, input { + display: block +} + +li { + display: list-item +} + +br::before { + content: "\\" +} diff --git a/src/display.nim b/src/display.nim new file mode 100644 index 00000000..d7d69c4a --- /dev/null +++ b/src/display.nim @@ -0,0 +1,395 @@ +import terminal +import options +import uri +import strutils +import unicode + +import buffer +import termattrs +import dom +import twtstr +import twtio +import config +import enums + +proc clearStatusMsg*(at: int) = + setCursorPos(0, at) + eraseLine() + +proc statusMsg*(str: string, at: int) = + clearStatusMsg(at) + print(str.ansiStyle(styleReverse).ansiReset()) + +type + RenderState = object + x: int + y: int + lastwidth: int + fmtline: string + rawline: string + centerqueue: seq[Node] + centerlen: int + blanklines: int + blankspaces: int + nextspaces: int + docenter: bool + indent: int + listval: int + +func newRenderState(): RenderState = + return RenderState(blanklines: 1) + +proc write(state: var RenderState, s: string) = + state.fmtline &= s + state.rawline &= s + +proc write(state: var RenderState, fs: string, rs: string) = + state.fmtline &= fs + state.rawline &= rs + +proc flushLine(buffer: Buffer, state: var RenderState) = + if state.rawline.len == 0: + inc state.blanklines + assert(state.rawline.runeLen() < buffer.width, "line too long:\n" & state.rawline) + buffer.writefmt(state.fmtline) + buffer.writeraw(state.rawline) + state.x = 0 + inc state.y + state.nextspaces = 0 + state.fmtline = "" + state.rawline = "" + +proc addSpaces(buffer: Buffer, state: var RenderState, n: int) = + if state.x + n > buffer.width: + buffer.flushLine(state) + return + state.blankspaces += n + state.write(' '.repeat(n)) + state.x += n + +proc writeWrappedText(buffer: Buffer, state: var RenderState, node: Node) = + state.lastwidth = 0 + var n = 0 + var fmtword = "" + var rawword = "" + var prevl = false + let fmttext = node.getFmtText() + for w in fmttext: + if w.len > 0 and w[0] == '\e': + fmtword &= w + continue + + for r in w.runes: + if r == Rune(' '): + if rawword.len > 0 and rawword[0] == ' ' and prevl: #first byte can't fool comparison to ascii + fmtword = fmtword.substr(1) + rawword = rawword.substr(1) + state.x -= 1 + prevl = false + state.write(fmtword, rawword) + fmtword = "" + rawword = "" + + if r == Rune('\n'): + state.write(fmtword, rawword) + buffer.flushLine(state) + rawword = "" + fmtword = "" + else: + fmtword &= r + rawword &= r + + state.x += r.width() + + if state.x >= buffer.width: + state.lastwidth = max(state.lastwidth, state.x) + buffer.flushLine(state) + state.x = rawword.width() + prevl = true + else: + state.lastwidth = max(state.lastwidth, state.x) + + inc n + + state.write(fmtword, rawword) + if prevl: + state.x += rawword.width() + prevl = false + + state.lastwidth = max(state.lastwidth, state.x) + +proc preAlignNode(buffer: Buffer, node: Node, state: var RenderState) = + let style = node.getStyle() + if state.rawline.len > 0 and node.firstNode() and state.blanklines == 0: + buffer.flushLine(state) + + if node.firstNode(): + while state.blanklines < max(style.margin, style.margintop): + buffer.flushLine(state) + state.indent += style.indent + + if state.rawline.len > 0 and state.blanklines == 0 and node.displayed(): + buffer.addSpaces(state, state.nextspaces) + state.nextspaces = 0 + if state.blankspaces < max(style.margin, style.marginleft): + buffer.addSpaces(state, max(style.margin, style.marginleft) - state.blankspaces) + + if style.centered and state.rawline.len == 0 and node.displayed(): + buffer.addSpaces(state, max(buffer.width div 2 - state.centerlen div 2, 0)) + state.centerlen = 0 + + if node.isElemNode() and style.display == DISPLAY_LIST_ITEM and state.indent > 0: + if state.blanklines == 0: + buffer.flushLine(state) + var listchar = "•" + #case elem.parentElement.tagType + #of TAG_UL: + # listchar = "•" + #of TAG_OL: + # inc state.listval + # listchar = $state.listval & ")" + #else: + # return + buffer.addSpaces(state, state.indent) + state.write(listchar) + state.x += listchar.runeLen() + buffer.addSpaces(state, 1) + +proc postAlignNode(buffer: Buffer, node: Node, state: var RenderState) = + let style = node.getStyle() + + if node.getRawLen() > 0: + state.blanklines = 0 + state.blankspaces = 0 + + if state.rawline.len > 0 and state.blanklines == 0: + state.nextspaces += max(style.margin, style.marginright) + #if node.lastNode() and (node.isTextNode() or elem.childNodes.len == 0): + # buffer.flushLine(state) + + if node.lastNode(): + while state.blanklines < max(style.margin, style.marginbottom): + buffer.flushLine(state) + state.indent -= style.indent + + if style.display == DISPLAY_LIST_ITEM and node.lastNode(): + buffer.flushLine(state) + +proc renderNode(buffer: Buffer, node: Node, state: var RenderState) = + if not (node.nodeType in {ELEMENT_NODE, TEXT_NODE}): + return + let style = node.getStyle() + if node.nodeType == ELEMENT_NODE: + if Element(node).tagType in {TAG_SCRIPT, TAG_STYLE, TAG_NOSCRIPT, TAG_TITLE}: + return + if style.hidden: return + + if not state.docenter: + if style.centered: + state.centerqueue.add(node) + if node.lastNode(): + state.docenter = true + state.centerlen = 0 + for node in state.centerqueue: + state.centerlen += node.getRawLen() + for node in state.centerqueue: + buffer.renderNode(node, state) + state.centerqueue.setLen(0) + state.docenter = false + return + else: + return + if state.centerqueue.len > 0: + state.docenter = true + state.centerlen = 0 + for node in state.centerqueue: + state.centerlen += node.getRawLen() + for node in state.centerqueue: + buffer.renderNode(node, state) + state.centerqueue.setLen(0) + state.docenter = false + + buffer.preAlignNode(node, state) + + node.x = state.x + node.y = state.y + buffer.writeWrappedText(state, node) + node.ex = state.x + node.ey = state.y + node.width = state.lastwidth - node.x - 1 + node.height = state.y - node.y + 1 + + buffer.postAlignNode(node, state) + +proc setLastHtmlLine(buffer: Buffer, state: var RenderState) = + if state.rawline.len != 0: + buffer.flushLine(state) + +proc renderHtml*(buffer: Buffer) = + var stack: seq[Node] + let first = buffer.document + stack.add(first) + + var state = newRenderState() + while stack.len > 0: + let currElem = stack.pop() + buffer.addNode(currElem) + buffer.renderNode(currElem, state) + var i = currElem.childNodes.len - 1 + while i >= 0: + stack.add(currElem.childNodes[i]) + i -= 1 + + buffer.setLastHtmlLine(state) + +proc drawHtml(buffer: Buffer) = + var state = newRenderState() + for node in buffer.nodes: + buffer.renderNode(node, state) + buffer.setLastHtmlLine(state) + +proc statusMsgForBuffer(buffer: Buffer) = + var msg = $(buffer.cursory + 1) & "/" & $(buffer.lastLine() + 1) & " (" & + $buffer.atPercentOf() & "%) " & + "<" & buffer.title & ">" + if buffer.hovertext.len > 0: + msg &= " " & buffer.hovertext + statusMsg(msg.maxString(buffer.width), buffer.height) + +proc cursorBufferPos(buffer: Buffer) = + var x = buffer.cursorx + var y = buffer.cursory - 1 - buffer.fromY + termGoto(x, y + 1) + +proc displayBuffer(buffer: Buffer) = + eraseScreen() + termGoto(0, 0) + + print(buffer.visibleText().ansiReset()) + +proc inputLoop(attrs: TermAttributes, buffer: Buffer): bool = + var s = "" + var feedNext = false + while true: + stdout.showCursor() + buffer.cursorBufferPos() + if not feedNext: + s = "" + else: + feedNext = false + let c = getch() + s &= c + let action = getNormalAction(s) + var redraw = false + var reshape = false + var nostatus = false + case action + of ACTION_QUIT: + eraseScreen() + return false + of ACTION_CURSOR_LEFT: redraw = buffer.cursorLeft() + of ACTION_CURSOR_DOWN: redraw = buffer.cursorDown() + of ACTION_CURSOR_UP: redraw = buffer.cursorUp() + of ACTION_CURSOR_RIGHT: redraw = buffer.cursorRight() + of ACTION_CURSOR_LINEBEGIN: buffer.cursorLineBegin() + of ACTION_CURSOR_LINEEND: buffer.cursorLineEnd() + of ACTION_CURSOR_NEXT_WORD: redraw = buffer.cursorNextWord() + of ACTION_CURSOR_PREV_WORD: redraw = buffer.cursorPrevWord() + of ACTION_CURSOR_NEXT_LINK: redraw = buffer.cursorNextLink() + of ACTION_CURSOR_PREV_LINK: redraw = buffer.cursorPrevLink() + of ACTION_PAGE_DOWN: redraw = buffer.pageDown() + of ACTION_PAGE_UP: redraw = buffer.pageUp() + of ACTION_HALF_PAGE_DOWN: redraw = buffer.halfPageDown() + of ACTION_HALF_PAGE_UP: redraw = buffer.halfPageUp() + of ACTION_CURSOR_FIRST_LINE: redraw = buffer.cursorFirstLine() + of ACTION_CURSOR_LAST_LINE: redraw = buffer.cursorLastLine() + of ACTION_CURSOR_TOP: redraw = buffer.cursorTop() + of ACTION_CURSOR_MIDDLE: redraw = buffer.cursorMiddle() + of ACTION_CURSOR_BOTTOM: redraw = buffer.cursorBottom() + of ACTION_CENTER_LINE: redraw = buffer.centerLine() + of ACTION_SCROLL_DOWN: redraw = buffer.scrollDown() + of ACTION_SCROLL_UP: redraw = buffer.scrollUp() + of ACTION_CLICK: + let selectedElem = buffer.findSelectedElement() + if selectedElem.isSome: + case selectedElem.get().tagType + of TAG_INPUT: + clearStatusMsg(buffer.height) + let status = readLine("TEXT: ", HtmlInputElement(selectedElem.get()).value, buffer.width) + if status: + reshape = true + redraw = true + else: discard + if selectedElem.get().getStyle().islink: + let anchor = HtmlAnchorElement(buffer.selectedlink.ancestor(TAG_A)).href + buffer.gotoLocation(parseUri(anchor)) + return true + of ACTION_CHANGE_LOCATION: + var url = $buffer.document.location + + clearStatusMsg(buffer.height) + let status = readLine("URL: ", url, buffer.width) + if status: + buffer.setLocation(parseUri(url)) + return true + of ACTION_LINE_INFO: + statusMsg("line " & $buffer.cursory & "/" & $buffer.lastLine() & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineLength(), buffer.width) + nostatus = true + of ACTION_FEED_NEXT: + feedNext = true + of ACTION_RELOAD: return true + of ACTION_RESHAPE: + reshape = true + redraw = true + of ACTION_REDRAW: redraw = true + else: discard + stdout.hideCursor() + + let prevlink = buffer.selectedlink + let sel = buffer.checkLinkSelection() + if sel: + buffer.clearText() + buffer.drawHtml() + termGoto(0, buffer.selectedlink.y - buffer.fromy) + stdout.eraseLine() + for i in buffer.selectedlink.y..buffer.selectedlink.ey: + if i < buffer.fromy + buffer.height - 1: + let line = buffer.fmttext[i] + print(line) + print('\n') + print("".ansiReset()) + + if prevlink != nil: + buffer.clearText() + buffer.drawHtml() + termGoto(0, prevlink.y - buffer.fromy) + for i in prevlink.y..prevlink.ey: + if i < buffer.fromy + buffer.height - 1: + let line = buffer.fmttext[i] + stdout.eraseLine() + print(line) + print('\n') + print("".ansiReset()) + + if buffer.refreshTermAttrs(): + redraw = true + reshape = true + + if reshape: + buffer.clearText() + buffer.drawHtml() + if redraw: + buffer.displayBuffer() + + if not nostatus: + buffer.statusMsgForBuffer() + else: + nostatus = false + +proc displayPage*(attrs: TermAttributes, buffer: Buffer): bool = + #buffer.printwrite = true + discard buffer.gotoAnchor() + buffer.displayBuffer() + buffer.statusMsgForBuffer() + return inputLoop(attrs, buffer) + diff --git a/src/dom.nim b/src/dom.nim new file mode 100644 index 00000000..9585456a --- /dev/null +++ b/src/dom.nim @@ -0,0 +1,331 @@ +import terminal +import uri +import unicode +import strutils +import tables + +import twtstr +import twtio +import enums +import style + +type + EventTarget* = ref EventTargetObj + EventTargetObj = object of RootObj + + Node* = ref NodeObj + NodeObj = object of EventTargetObj + nodeType*: NodeType + childNodes*: seq[Node] + firstChild*: Node + isConnected*: bool + lastChild*: Node + nextSibling*: Node + previousSibling*: Node + parentNode*: Node + parentElement*: Element + ownerDocument*: Document + + rawtext*: string + fmttext*: seq[string] + x*: int + y*: int + ex*: int + ey*: int + width*: int + height*: int + hidden*: bool + + Attr* = ref AttrObj + AttrObj = object of NodeObj + namespaceURI*: string + prefix*: string + localName*: string + name*: string + value*: string + ownerElement*: Element + + Document* = ref DocumentObj + DocumentObj = object of NodeObj + location*: Uri + + CharacterData* = ref CharacterDataObj + CharacterDataObj = object of NodeObj + data*: string + length*: int + + Text* = ref TextObj + TextObj = object of CharacterDataObj + wholeText*: string + + Comment* = ref CommentObj + CommentObj = object of CharacterDataObj + + Element* = ref ElementObj + ElementObj = object of NodeObj + namespaceURI*: string + prefix*: string + localName*: string + tagName*: string + tagType*: TagType + + id*: string + classList*: seq[string] + attributes*: Table[string, Attr] + style*: CSS2Properties + + HTMLElement* = ref HTMLElementObj + HTMLElementObj = object of ElementObj + + HTMLInputElement* = ref HTMLInputElementObj + HTMLInputElementObj = object of HTMLElementObj + itype*: InputType + autofocus*: bool + required*: bool + value*: string + size*: int + + HTMLAnchorElement* = ref HTMLAnchorElementObj + HTMLAnchorElementObj = object of HTMLElementObj + href*: string + + HTMLSelectElement* = ref HTMLSelectElementObj + HTMLSelectElementObj = object of HTMLElementObj + name*: string + value*: string + valueSet*: bool + + HTMLOptionElement* = ref HTMLOptionElementObj + HTMLOptionElementObj = object of HTMLElementObj + value*: string + + HTMLHeadingElement* = ref HTMLHeadingElementObj + HTMLHeadingElementObj = object of HTMLElementObj + rank*: uint16 + + HTMLBRElement* = ref HTMLBRElementObj + HTMLBRElementObj = object of HTMLElementObj + + +func getTagTypeMap(): Table[string, TagType] = + for i in low(TagType) .. high(TagType): + let enumname = $TagType(i) + let tagname = enumname.split('_')[1..^1].join("_").tolower() + result[tagname] = TagType(i) + +func getInputTypeMap(): Table[string, InputType] = + for i in low(InputType) .. high(InputType): + let enumname = $InputType(i) + let tagname = enumname.split('_')[1..^1].join("_").tolower() + result[tagname] = InputType(i) + +const tagTypeMap = getTagTypeMap() +const inputTypeMap = getInputTypeMap() + +func tagType*(s: string): TagType = + if tagTypeMap.hasKey(s): + return tagTypeMap[s] + else: + return TAG_UNKNOWN + +func inputType*(s: string): InputType = + if inputTypeMap.hasKey(s): + return inputTypeMap[s] + else: + return INPUT_UNKNOWN + +#TODO +func nodeAttr*(node: Node): HtmlElement = + case node.nodeType + of TEXT_NODE: return HtmlElement(node.parentElement) + of ELEMENT_NODE: return HtmlElement(node) + else: assert(false) + +func getStyle*(node: Node): CSS2Properties = + case node.nodeType + of TEXT_NODE: return node.parentElement.style + of ELEMENT_NODE: return Element(node).style + else: assert(false) + +func displayed*(node: Node): bool = + return node.rawtext.len > 0 and node.getStyle().display != DISPLAY_NONE + +func isTextNode*(node: Node): bool = + return node.nodeType == TEXT_NODE + +func isElemNode*(node: Node): bool = + return node.nodeType == ELEMENT_NODE + +func isComment*(node: Node): bool = + return node.nodeType == COMMENT_NODE + +func isCData*(node: Node): bool = + return node.nodeType == CDATA_SECTION_NODE + +func isDocument*(node: Node): bool = + return node.nodeType == DOCUMENT_NODE + +func getFmtLen*(htmlNode: Node): int = + return htmlNode.fmttext.join().runeLen() + +func getRawLen*(htmlNode: Node): int = + return htmlNode.rawtext.runeLen() + +func firstNode*(htmlNode: Node): bool = + return htmlNode.parentElement != nil and htmlNode.parentElement.childNodes[0] == htmlNode + +func lastNode*(htmlNode: Node): bool = + return htmlNode.parentElement != nil and htmlNode.parentElement.childNodes[^1] == htmlNode + +func toInputType*(str: string): InputType = + case str + of "button": INPUT_BUTTON + of "checkbox": INPUT_CHECKBOX + of "color": INPUT_COLOR + of "date": INPUT_DATE + of "datetime_local": INPUT_DATETIME_LOCAL + of "email": INPUT_EMAIL + of "file": INPUT_FILE + of "hidden": INPUT_HIDDEN + of "image": INPUT_IMAGE + of "month": INPUT_MONTH + of "number": INPUT_NUMBER + of "password": INPUT_PASSWORD + of "radio": INPUT_RADIO + of "range": INPUT_RANGE + of "reset": INPUT_RESET + of "search": INPUT_SEARCH + of "submit": INPUT_SUBMIT + of "tel": INPUT_TEL + of "text": INPUT_TEXT + of "time": INPUT_TIME + of "url": INPUT_URL + of "week": INPUT_WEEK + else: INPUT_UNKNOWN + +func toInputSize*(str: string): int = + if str.len == 0: + return 20 + for c in str: + if not c.isDigit(): + return 20 + return str.parseInt() + +func getFmtInput(inputElement: HtmlInputElement): seq[string] = + case inputElement.itype + of INPUT_TEXT, INPUT_SEARCH: + let valueFit = fitValueToSize(inputElement.value, inputElement.size) + return valueFit.ansiStyle(styleUnderscore).ansiReset().buttonFmt() + of INPUT_SUBMIT: + return inputElement.value.buttonFmt() + else: discard + +func getRawInput(inputElement: HtmlInputElement): string = + case inputElement.itype + of INPUT_TEXT, INPUT_SEARCH: + return inputElement.value.fitValueToSize(inputElement.size).buttonRaw() + of INPUT_SUBMIT: + return inputElement.value.buttonRaw() + else: discard + +#TODO +func ancestor*(htmlNode: Node, tagType: TagType): HtmlElement = + result = HtmlElement(htmlNode.parentElement) + while result != nil and result.tagType != tagType: + result = HtmlElement(result.parentElement) + +proc getRawText*(htmlNode: Node): string = + if htmlNode.isElemNode(): + case HtmlElement(htmlNode).tagType + of TAG_INPUT: return HtmlInputElement(htmlNode).getRawInput() + else: return "" + elif htmlNode.isTextNode(): + let chardata = CharacterData(htmlNode) + if htmlNode.parentElement != nil and htmlNode.parentElement.tagType != TAG_PRE: + result = chardata.data.remove("\n") + if unicode.strip(result).runeLen() > 0: + if htmlNode.getStyle().display != DISPLAY_INLINE: + result = unicode.strip(result) + else: + result = "" + else: + result = unicode.strip(chardata.data) + if htmlNode.parentElement != nil and htmlNode.parentElement.tagType == TAG_OPTION: + result = result.buttonRaw() + else: + assert(false) + +func getFmtText*(htmlNode: Node): seq[string] = + if htmlNode.isElemNode(): + case HtmlElement(htmlNode).tagType + of TAG_INPUT: return HtmlInputElement(htmlNode).getFmtInput() + else: return @[] + elif htmlNode.isTextNode(): + let chardata = CharacterData(htmlNode) + result &= chardata.data + if htmlNode.parentElement != nil: + if htmlNode.parentElement.style.islink: + result = result.ansiFgColor(fgBlue).ansiReset() + let anchor = htmlNode.ancestor(TAG_A) + if anchor != nil and anchor.style.selected: + result = result.ansiStyle(styleUnderscore).ansiReset() + + if htmlNode.parentElement.tagType == TAG_OPTION: + result = result.ansiFgColor(fgRed).ansiReset() + + if htmlNode.parentElement.style.bold: + result = result.ansiStyle(styleBright).ansiReset() + if htmlNode.parentElement.style.italic: + result = result.ansiStyle(styleItalic).ansiReset() + if htmlNode.parentElement.style.underscore: + result = result.ansiStyle(styleUnderscore).ansiReset() + else: + assert(false, "Uhhhh I'm pretty sure we should have parent elements for text nodes?" & htmlNode.rawtext) + else: + assert(false) + +func newDocument*(): Document = + new(result) + result.nodeType = DOCUMENT_NODE + +func newText*(): Text = + new(result) + result.nodeType = TEXT_NODE + +func newComment*(): Comment = + new(result) + result.nodeType = COMMENT_NODE + +func newHtmlElement*(tagType: TagType): HTMLElement = + case tagType + of TAG_INPUT: + result = new(HTMLInputElement) + of TAG_A: + result = new(HTMLAnchorElement) + of TAG_SELECT: + result = new(HTMLSelectElement) + of TAG_OPTION: + result = new(HTMLOptionElement) + of TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6: + result = new(HTMLHeadingElement) + of TAG_BR: + result = new(HTMLBRElement) + else: + new(result) + + result.nodeType = ELEMENT_NODE + result.tagType = tagType + result.style = new(CSS2Properties) + +func newAttr*(parent: Element, key: string, value: string): Attr = + new(result) + result.nodeType = ATTRIBUTE_NODE + result.ownerElement = parent + result.name = key + result.value = value + +func getAttrValue*(element: Element, s: string): string = + let attr = element.attributes.getOrDefault(s, nil) + if attr != nil: + return attr.value + return "" diff --git a/src/entity b/src/entity new file mode 100755 index 00000000..05f6705f Binary files /dev/null and b/src/entity differ diff --git a/src/entity.json b/src/entity.json new file mode 100644 index 00000000..557170b4 --- /dev/null +++ b/src/entity.json @@ -0,0 +1,2233 @@ +{ + "Æ": { "codepoints": [198], "characters": "\u00C6" }, + "Æ": { "codepoints": [198], "characters": "\u00C6" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "Á": { "codepoints": [193], "characters": "\u00C1" }, + "Á": { "codepoints": [193], "characters": "\u00C1" }, + "Ă": { "codepoints": [258], "characters": "\u0102" }, + "Â": { "codepoints": [194], "characters": "\u00C2" }, + "Â": { "codepoints": [194], "characters": "\u00C2" }, + "А": { "codepoints": [1040], "characters": "\u0410" }, + "𝔄": { "codepoints": [120068], "characters": "\uD835\uDD04" }, + "À": { "codepoints": [192], "characters": "\u00C0" }, + "À": { "codepoints": [192], "characters": "\u00C0" }, + "Α": { "codepoints": [913], "characters": "\u0391" }, + "Ā": { "codepoints": [256], "characters": "\u0100" }, + "⩓": { "codepoints": [10835], "characters": "\u2A53" }, + "Ą": { "codepoints": [260], "characters": "\u0104" }, + "𝔸": { "codepoints": [120120], "characters": "\uD835\uDD38" }, + "⁡": { "codepoints": [8289], "characters": "\u2061" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "𝒜": { "codepoints": [119964], "characters": "\uD835\uDC9C" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + "Ã": { "codepoints": [195], "characters": "\u00C3" }, + "Ã": { "codepoints": [195], "characters": "\u00C3" }, + "Ä": { "codepoints": [196], "characters": "\u00C4" }, + "Ä": { "codepoints": [196], "characters": "\u00C4" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⫧": { "codepoints": [10983], "characters": "\u2AE7" }, + "⌆": { "codepoints": [8966], "characters": "\u2306" }, + "Б": { "codepoints": [1041], "characters": "\u0411" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "Β": { "codepoints": [914], "characters": "\u0392" }, + "𝔅": { "codepoints": [120069], "characters": "\uD835\uDD05" }, + "𝔹": { "codepoints": [120121], "characters": "\uD835\uDD39" }, + "˘": { "codepoints": [728], "characters": "\u02D8" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "Ч": { "codepoints": [1063], "characters": "\u0427" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "Ć": { "codepoints": [262], "characters": "\u0106" }, + "⋒": { "codepoints": [8914], "characters": "\u22D2" }, + "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, + "ℭ": { "codepoints": [8493], "characters": "\u212D" }, + "Č": { "codepoints": [268], "characters": "\u010C" }, + "Ç": { "codepoints": [199], "characters": "\u00C7" }, + "Ç": { "codepoints": [199], "characters": "\u00C7" }, + "Ĉ": { "codepoints": [264], "characters": "\u0108" }, + "∰": { "codepoints": [8752], "characters": "\u2230" }, + "Ċ": { "codepoints": [266], "characters": "\u010A" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "ℭ": { "codepoints": [8493], "characters": "\u212D" }, + "Χ": { "codepoints": [935], "characters": "\u03A7" }, + "⊙": { "codepoints": [8857], "characters": "\u2299" }, + "⊖": { "codepoints": [8854], "characters": "\u2296" }, + "⊕": { "codepoints": [8853], "characters": "\u2295" }, + "⊗": { "codepoints": [8855], "characters": "\u2297" }, + "∲": { "codepoints": [8754], "characters": "\u2232" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "∷": { "codepoints": [8759], "characters": "\u2237" }, + "⩴": { "codepoints": [10868], "characters": "\u2A74" }, + "≡": { "codepoints": [8801], "characters": "\u2261" }, + "∯": { "codepoints": [8751], "characters": "\u222F" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "ℂ": { "codepoints": [8450], "characters": "\u2102" }, + "∐": { "codepoints": [8720], "characters": "\u2210" }, + "∳": { "codepoints": [8755], "characters": "\u2233" }, + "⨯": { "codepoints": [10799], "characters": "\u2A2F" }, + "𝒞": { "codepoints": [119966], "characters": "\uD835\uDC9E" }, + "⋓": { "codepoints": [8915], "characters": "\u22D3" }, + "≍": { "codepoints": [8781], "characters": "\u224D" }, + "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, + "⤑": { "codepoints": [10513], "characters": "\u2911" }, + "Ђ": { "codepoints": [1026], "characters": "\u0402" }, + "Ѕ": { "codepoints": [1029], "characters": "\u0405" }, + "Џ": { "codepoints": [1039], "characters": "\u040F" }, + "‡": { "codepoints": [8225], "characters": "\u2021" }, + "↡": { "codepoints": [8609], "characters": "\u21A1" }, + "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, + "Ď": { "codepoints": [270], "characters": "\u010E" }, + "Д": { "codepoints": [1044], "characters": "\u0414" }, + "∇": { "codepoints": [8711], "characters": "\u2207" }, + "Δ": { "codepoints": [916], "characters": "\u0394" }, + "𝔇": { "codepoints": [120071], "characters": "\uD835\uDD07" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "˙": { "codepoints": [729], "characters": "\u02D9" }, + "˝": { "codepoints": [733], "characters": "\u02DD" }, + "`": { "codepoints": [96], "characters": "\u0060" }, + "˜": { "codepoints": [732], "characters": "\u02DC" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, + "𝔻": { "codepoints": [120123], "characters": "\uD835\uDD3B" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "⃜": { "codepoints": [8412], "characters": "\u20DC" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "∯": { "codepoints": [8751], "characters": "\u222F" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "⊨": { "codepoints": [8872], "characters": "\u22A8" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "⤓": { "codepoints": [10515], "characters": "\u2913" }, + "⇵": { "codepoints": [8693], "characters": "\u21F5" }, + "̑": { "codepoints": [785], "characters": "\u0311" }, + "⥐": { "codepoints": [10576], "characters": "\u2950" }, + "⥞": { "codepoints": [10590], "characters": "\u295E" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "⥖": { "codepoints": [10582], "characters": "\u2956" }, + "⥟": { "codepoints": [10591], "characters": "\u295F" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⥗": { "codepoints": [10583], "characters": "\u2957" }, + "⊤": { "codepoints": [8868], "characters": "\u22A4" }, + "↧": { "codepoints": [8615], "characters": "\u21A7" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "𝒟": { "codepoints": [119967], "characters": "\uD835\uDC9F" }, + "Đ": { "codepoints": [272], "characters": "\u0110" }, + "Ŋ": { "codepoints": [330], "characters": "\u014A" }, + "Ð": { "codepoints": [208], "characters": "\u00D0" }, + "Ð": { "codepoints": [208], "characters": "\u00D0" }, + "É": { "codepoints": [201], "characters": "\u00C9" }, + "É": { "codepoints": [201], "characters": "\u00C9" }, + "Ě": { "codepoints": [282], "characters": "\u011A" }, + "Ê": { "codepoints": [202], "characters": "\u00CA" }, + "Ê": { "codepoints": [202], "characters": "\u00CA" }, + "Э": { "codepoints": [1069], "characters": "\u042D" }, + "Ė": { "codepoints": [278], "characters": "\u0116" }, + "𝔈": { "codepoints": [120072], "characters": "\uD835\uDD08" }, + "È": { "codepoints": [200], "characters": "\u00C8" }, + "È": { "codepoints": [200], "characters": "\u00C8" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "Ē": { "codepoints": [274], "characters": "\u0112" }, + "◻": { "codepoints": [9723], "characters": "\u25FB" }, + "▫": { "codepoints": [9643], "characters": "\u25AB" }, + "Ę": { "codepoints": [280], "characters": "\u0118" }, + "𝔼": { "codepoints": [120124], "characters": "\uD835\uDD3C" }, + "Ε": { "codepoints": [917], "characters": "\u0395" }, + "⩵": { "codepoints": [10869], "characters": "\u2A75" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "ℰ": { "codepoints": [8496], "characters": "\u2130" }, + "⩳": { "codepoints": [10867], "characters": "\u2A73" }, + "Η": { "codepoints": [919], "characters": "\u0397" }, + "Ë": { "codepoints": [203], "characters": "\u00CB" }, + "Ë": { "codepoints": [203], "characters": "\u00CB" }, + "∃": { "codepoints": [8707], "characters": "\u2203" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "Ф": { "codepoints": [1060], "characters": "\u0424" }, + "𝔉": { "codepoints": [120073], "characters": "\uD835\uDD09" }, + "◼": { "codepoints": [9724], "characters": "\u25FC" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "𝔽": { "codepoints": [120125], "characters": "\uD835\uDD3D" }, + "∀": { "codepoints": [8704], "characters": "\u2200" }, + "ℱ": { "codepoints": [8497], "characters": "\u2131" }, + "ℱ": { "codepoints": [8497], "characters": "\u2131" }, + "Ѓ": { "codepoints": [1027], "characters": "\u0403" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + "Γ": { "codepoints": [915], "characters": "\u0393" }, + "Ϝ": { "codepoints": [988], "characters": "\u03DC" }, + "Ğ": { "codepoints": [286], "characters": "\u011E" }, + "Ģ": { "codepoints": [290], "characters": "\u0122" }, + "Ĝ": { "codepoints": [284], "characters": "\u011C" }, + "Г": { "codepoints": [1043], "characters": "\u0413" }, + "Ġ": { "codepoints": [288], "characters": "\u0120" }, + "𝔊": { "codepoints": [120074], "characters": "\uD835\uDD0A" }, + "⋙": { "codepoints": [8921], "characters": "\u22D9" }, + "𝔾": { "codepoints": [120126], "characters": "\uD835\uDD3E" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⪢": { "codepoints": [10914], "characters": "\u2AA2" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "𝒢": { "codepoints": [119970], "characters": "\uD835\uDCA2" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "Ъ": { "codepoints": [1066], "characters": "\u042A" }, + "ˇ": { "codepoints": [711], "characters": "\u02C7" }, + "^": { "codepoints": [94], "characters": "\u005E" }, + "Ĥ": { "codepoints": [292], "characters": "\u0124" }, + "ℌ": { "codepoints": [8460], "characters": "\u210C" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "ℍ": { "codepoints": [8461], "characters": "\u210D" }, + "─": { "codepoints": [9472], "characters": "\u2500" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "Ħ": { "codepoints": [294], "characters": "\u0126" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "Е": { "codepoints": [1045], "characters": "\u0415" }, + "IJ": { "codepoints": [306], "characters": "\u0132" }, + "Ё": { "codepoints": [1025], "characters": "\u0401" }, + "Í": { "codepoints": [205], "characters": "\u00CD" }, + "Í": { "codepoints": [205], "characters": "\u00CD" }, + "Î": { "codepoints": [206], "characters": "\u00CE" }, + "Î": { "codepoints": [206], "characters": "\u00CE" }, + "И": { "codepoints": [1048], "characters": "\u0418" }, + "İ": { "codepoints": [304], "characters": "\u0130" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "Ì": { "codepoints": [204], "characters": "\u00CC" }, + "Ì": { "codepoints": [204], "characters": "\u00CC" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "Ī": { "codepoints": [298], "characters": "\u012A" }, + "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "∬": { "codepoints": [8748], "characters": "\u222C" }, + "∫": { "codepoints": [8747], "characters": "\u222B" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "⁣": { "codepoints": [8291], "characters": "\u2063" }, + "⁢": { "codepoints": [8290], "characters": "\u2062" }, + "Į": { "codepoints": [302], "characters": "\u012E" }, + "𝕀": { "codepoints": [120128], "characters": "\uD835\uDD40" }, + "Ι": { "codepoints": [921], "characters": "\u0399" }, + "ℐ": { "codepoints": [8464], "characters": "\u2110" }, + "Ĩ": { "codepoints": [296], "characters": "\u0128" }, + "І": { "codepoints": [1030], "characters": "\u0406" }, + "Ï": { "codepoints": [207], "characters": "\u00CF" }, + "Ï": { "codepoints": [207], "characters": "\u00CF" }, + "Ĵ": { "codepoints": [308], "characters": "\u0134" }, + "Й": { "codepoints": [1049], "characters": "\u0419" }, + "𝔍": { "codepoints": [120077], "characters": "\uD835\uDD0D" }, + "𝕁": { "codepoints": [120129], "characters": "\uD835\uDD41" }, + "𝒥": { "codepoints": [119973], "characters": "\uD835\uDCA5" }, + "Ј": { "codepoints": [1032], "characters": "\u0408" }, + "Є": { "codepoints": [1028], "characters": "\u0404" }, + "Х": { "codepoints": [1061], "characters": "\u0425" }, + "Ќ": { "codepoints": [1036], "characters": "\u040C" }, + "Κ": { "codepoints": [922], "characters": "\u039A" }, + "Ķ": { "codepoints": [310], "characters": "\u0136" }, + "К": { "codepoints": [1050], "characters": "\u041A" }, + "𝔎": { "codepoints": [120078], "characters": "\uD835\uDD0E" }, + "𝕂": { "codepoints": [120130], "characters": "\uD835\uDD42" }, + "𝒦": { "codepoints": [119974], "characters": "\uD835\uDCA6" }, + "Љ": { "codepoints": [1033], "characters": "\u0409" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "Ĺ": { "codepoints": [313], "characters": "\u0139" }, + "Λ": { "codepoints": [923], "characters": "\u039B" }, + "⟪": { "codepoints": [10218], "characters": "\u27EA" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "↞": { "codepoints": [8606], "characters": "\u219E" }, + "Ľ": { "codepoints": [317], "characters": "\u013D" }, + "Ļ": { "codepoints": [315], "characters": "\u013B" }, + "Л": { "codepoints": [1051], "characters": "\u041B" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "⇤": { "codepoints": [8676], "characters": "\u21E4" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⌈": { "codepoints": [8968], "characters": "\u2308" }, + "⟦": { "codepoints": [10214], "characters": "\u27E6" }, + "⥡": { "codepoints": [10593], "characters": "\u2961" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⥙": { "codepoints": [10585], "characters": "\u2959" }, + "⌊": { "codepoints": [8970], "characters": "\u230A" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⥎": { "codepoints": [10574], "characters": "\u294E" }, + "⊣": { "codepoints": [8867], "characters": "\u22A3" }, + "↤": { "codepoints": [8612], "characters": "\u21A4" }, + "⥚": { "codepoints": [10586], "characters": "\u295A" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⧏": { "codepoints": [10703], "characters": "\u29CF" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "⥑": { "codepoints": [10577], "characters": "\u2951" }, + "⥠": { "codepoints": [10592], "characters": "\u2960" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "⥘": { "codepoints": [10584], "characters": "\u2958" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⥒": { "codepoints": [10578], "characters": "\u2952" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "⪡": { "codepoints": [10913], "characters": "\u2AA1" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "𝔏": { "codepoints": [120079], "characters": "\uD835\uDD0F" }, + "⋘": { "codepoints": [8920], "characters": "\u22D8" }, + "⇚": { "codepoints": [8666], "characters": "\u21DA" }, + "Ŀ": { "codepoints": [319], "characters": "\u013F" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "𝕃": { "codepoints": [120131], "characters": "\uD835\uDD43" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "↰": { "codepoints": [8624], "characters": "\u21B0" }, + "Ł": { "codepoints": [321], "characters": "\u0141" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + "⤅": { "codepoints": [10501], "characters": "\u2905" }, + "М": { "codepoints": [1052], "characters": "\u041C" }, + " ": { "codepoints": [8287], "characters": "\u205F" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "𝔐": { "codepoints": [120080], "characters": "\uD835\uDD10" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "𝕄": { "codepoints": [120132], "characters": "\uD835\uDD44" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "Μ": { "codepoints": [924], "characters": "\u039C" }, + "Њ": { "codepoints": [1034], "characters": "\u040A" }, + "Ń": { "codepoints": [323], "characters": "\u0143" }, + "Ň": { "codepoints": [327], "characters": "\u0147" }, + "Ņ": { "codepoints": [325], "characters": "\u0145" }, + "Н": { "codepoints": [1053], "characters": "\u041D" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + " ": { "codepoints": [10], "characters": "\u000A" }, + "𝔑": { "codepoints": [120081], "characters": "\uD835\uDD11" }, + "⁠": { "codepoints": [8288], "characters": "\u2060" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + "ℕ": { "codepoints": [8469], "characters": "\u2115" }, + "⫬": { "codepoints": [10988], "characters": "\u2AEC" }, + "≢": { "codepoints": [8802], "characters": "\u2262" }, + "≭": { "codepoints": [8813], "characters": "\u226D" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "≠": { "codepoints": [8800], "characters": "\u2260" }, + "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, + "≹": { "codepoints": [8825], "characters": "\u2279" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "≵": { "codepoints": [8821], "characters": "\u2275" }, + "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, + "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⧏̸": { "codepoints": [10703, 824], "characters": "\u29CF\u0338" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "≸": { "codepoints": [8824], "characters": "\u2278" }, + "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "≴": { "codepoints": [8820], "characters": "\u2274" }, + "⪢̸": { "codepoints": [10914, 824], "characters": "\u2AA2\u0338" }, + "⪡̸": { "codepoints": [10913, 824], "characters": "\u2AA1\u0338" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⋠": { "codepoints": [8928], "characters": "\u22E0" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⧐̸": { "codepoints": [10704, 824], "characters": "\u29D0\u0338" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "⊏̸": { "codepoints": [8847, 824], "characters": "\u228F\u0338" }, + "⋢": { "codepoints": [8930], "characters": "\u22E2" }, + "⊐̸": { "codepoints": [8848, 824], "characters": "\u2290\u0338" }, + "⋣": { "codepoints": [8931], "characters": "\u22E3" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "⋡": { "codepoints": [8929], "characters": "\u22E1" }, + "≿̸": { "codepoints": [8831, 824], "characters": "\u227F\u0338" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "≁": { "codepoints": [8769], "characters": "\u2241" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "≇": { "codepoints": [8775], "characters": "\u2247" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "𝒩": { "codepoints": [119977], "characters": "\uD835\uDCA9" }, + "Ñ": { "codepoints": [209], "characters": "\u00D1" }, + "Ñ": { "codepoints": [209], "characters": "\u00D1" }, + "Ν": { "codepoints": [925], "characters": "\u039D" }, + "Œ": { "codepoints": [338], "characters": "\u0152" }, + "Ó": { "codepoints": [211], "characters": "\u00D3" }, + "Ó": { "codepoints": [211], "characters": "\u00D3" }, + "Ô": { "codepoints": [212], "characters": "\u00D4" }, + "Ô": { "codepoints": [212], "characters": "\u00D4" }, + "О": { "codepoints": [1054], "characters": "\u041E" }, + "Ő": { "codepoints": [336], "characters": "\u0150" }, + "𝔒": { "codepoints": [120082], "characters": "\uD835\uDD12" }, + "Ò": { "codepoints": [210], "characters": "\u00D2" }, + "Ò": { "codepoints": [210], "characters": "\u00D2" }, + "Ō": { "codepoints": [332], "characters": "\u014C" }, + "Ω": { "codepoints": [937], "characters": "\u03A9" }, + "Ο": { "codepoints": [927], "characters": "\u039F" }, + "𝕆": { "codepoints": [120134], "characters": "\uD835\uDD46" }, + "“": { "codepoints": [8220], "characters": "\u201C" }, + "‘": { "codepoints": [8216], "characters": "\u2018" }, + "⩔": { "codepoints": [10836], "characters": "\u2A54" }, + "𝒪": { "codepoints": [119978], "characters": "\uD835\uDCAA" }, + "Ø": { "codepoints": [216], "characters": "\u00D8" }, + "Ø": { "codepoints": [216], "characters": "\u00D8" }, + "Õ": { "codepoints": [213], "characters": "\u00D5" }, + "Õ": { "codepoints": [213], "characters": "\u00D5" }, + "⨷": { "codepoints": [10807], "characters": "\u2A37" }, + "Ö": { "codepoints": [214], "characters": "\u00D6" }, + "Ö": { "codepoints": [214], "characters": "\u00D6" }, + "‾": { "codepoints": [8254], "characters": "\u203E" }, + "⏞": { "codepoints": [9182], "characters": "\u23DE" }, + "⎴": { "codepoints": [9140], "characters": "\u23B4" }, + "⏜": { "codepoints": [9180], "characters": "\u23DC" }, + "∂": { "codepoints": [8706], "characters": "\u2202" }, + "П": { "codepoints": [1055], "characters": "\u041F" }, + "𝔓": { "codepoints": [120083], "characters": "\uD835\uDD13" }, + "Φ": { "codepoints": [934], "characters": "\u03A6" }, + "Π": { "codepoints": [928], "characters": "\u03A0" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "ℌ": { "codepoints": [8460], "characters": "\u210C" }, + "ℙ": { "codepoints": [8473], "characters": "\u2119" }, + "⪻": { "codepoints": [10939], "characters": "\u2ABB" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "″": { "codepoints": [8243], "characters": "\u2033" }, + "∏": { "codepoints": [8719], "characters": "\u220F" }, + "∷": { "codepoints": [8759], "characters": "\u2237" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "𝒫": { "codepoints": [119979], "characters": "\uD835\uDCAB" }, + "Ψ": { "codepoints": [936], "characters": "\u03A8" }, + """: { "codepoints": [34], "characters": "\u0022" }, + """: { "codepoints": [34], "characters": "\u0022" }, + "𝔔": { "codepoints": [120084], "characters": "\uD835\uDD14" }, + "ℚ": { "codepoints": [8474], "characters": "\u211A" }, + "𝒬": { "codepoints": [119980], "characters": "\uD835\uDCAC" }, + "⤐": { "codepoints": [10512], "characters": "\u2910" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "Ŕ": { "codepoints": [340], "characters": "\u0154" }, + "⟫": { "codepoints": [10219], "characters": "\u27EB" }, + "↠": { "codepoints": [8608], "characters": "\u21A0" }, + "⤖": { "codepoints": [10518], "characters": "\u2916" }, + "Ř": { "codepoints": [344], "characters": "\u0158" }, + "Ŗ": { "codepoints": [342], "characters": "\u0156" }, + "Р": { "codepoints": [1056], "characters": "\u0420" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "⥯": { "codepoints": [10607], "characters": "\u296F" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "Ρ": { "codepoints": [929], "characters": "\u03A1" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "⇥": { "codepoints": [8677], "characters": "\u21E5" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⌉": { "codepoints": [8969], "characters": "\u2309" }, + "⟧": { "codepoints": [10215], "characters": "\u27E7" }, + "⥝": { "codepoints": [10589], "characters": "\u295D" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⥕": { "codepoints": [10581], "characters": "\u2955" }, + "⌋": { "codepoints": [8971], "characters": "\u230B" }, + "⊢": { "codepoints": [8866], "characters": "\u22A2" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "⥛": { "codepoints": [10587], "characters": "\u295B" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "⧐": { "codepoints": [10704], "characters": "\u29D0" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "⥏": { "codepoints": [10575], "characters": "\u294F" }, + "⥜": { "codepoints": [10588], "characters": "\u295C" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "⥔": { "codepoints": [10580], "characters": "\u2954" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⥓": { "codepoints": [10579], "characters": "\u2953" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "ℝ": { "codepoints": [8477], "characters": "\u211D" }, + "⥰": { "codepoints": [10608], "characters": "\u2970" }, + "⇛": { "codepoints": [8667], "characters": "\u21DB" }, + "ℛ": { "codepoints": [8475], "characters": "\u211B" }, + "↱": { "codepoints": [8625], "characters": "\u21B1" }, + "⧴": { "codepoints": [10740], "characters": "\u29F4" }, + "Щ": { "codepoints": [1065], "characters": "\u0429" }, + "Ш": { "codepoints": [1064], "characters": "\u0428" }, + "Ь": { "codepoints": [1068], "characters": "\u042C" }, + "Ś": { "codepoints": [346], "characters": "\u015A" }, + "⪼": { "codepoints": [10940], "characters": "\u2ABC" }, + "Š": { "codepoints": [352], "characters": "\u0160" }, + "Ş": { "codepoints": [350], "characters": "\u015E" }, + "Ŝ": { "codepoints": [348], "characters": "\u015C" }, + "С": { "codepoints": [1057], "characters": "\u0421" }, + "𝔖": { "codepoints": [120086], "characters": "\uD835\uDD16" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "Σ": { "codepoints": [931], "characters": "\u03A3" }, + "∘": { "codepoints": [8728], "characters": "\u2218" }, + "𝕊": { "codepoints": [120138], "characters": "\uD835\uDD4A" }, + "√": { "codepoints": [8730], "characters": "\u221A" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "⊓": { "codepoints": [8851], "characters": "\u2293" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "⊔": { "codepoints": [8852], "characters": "\u2294" }, + "𝒮": { "codepoints": [119982], "characters": "\uD835\uDCAE" }, + "⋆": { "codepoints": [8902], "characters": "\u22C6" }, + "⋐": { "codepoints": [8912], "characters": "\u22D0" }, + "⋐": { "codepoints": [8912], "characters": "\u22D0" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "∑": { "codepoints": [8721], "characters": "\u2211" }, + "⋑": { "codepoints": [8913], "characters": "\u22D1" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⋑": { "codepoints": [8913], "characters": "\u22D1" }, + "Þ": { "codepoints": [222], "characters": "\u00DE" }, + "Þ": { "codepoints": [222], "characters": "\u00DE" }, + "™": { "codepoints": [8482], "characters": "\u2122" }, + "Ћ": { "codepoints": [1035], "characters": "\u040B" }, + "Ц": { "codepoints": [1062], "characters": "\u0426" }, + " ": { "codepoints": [9], "characters": "\u0009" }, + "Τ": { "codepoints": [932], "characters": "\u03A4" }, + "Ť": { "codepoints": [356], "characters": "\u0164" }, + "Ţ": { "codepoints": [354], "characters": "\u0162" }, + "Т": { "codepoints": [1058], "characters": "\u0422" }, + "𝔗": { "codepoints": [120087], "characters": "\uD835\uDD17" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "Θ": { "codepoints": [920], "characters": "\u0398" }, + "  ": { "codepoints": [8287, 8202], "characters": "\u205F\u200A" }, + " ": { "codepoints": [8201], "characters": "\u2009" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "≅": { "codepoints": [8773], "characters": "\u2245" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "𝕋": { "codepoints": [120139], "characters": "\uD835\uDD4B" }, + "⃛": { "codepoints": [8411], "characters": "\u20DB" }, + "𝒯": { "codepoints": [119983], "characters": "\uD835\uDCAF" }, + "Ŧ": { "codepoints": [358], "characters": "\u0166" }, + "Ú": { "codepoints": [218], "characters": "\u00DA" }, + "Ú": { "codepoints": [218], "characters": "\u00DA" }, + "↟": { "codepoints": [8607], "characters": "\u219F" }, + "⥉": { "codepoints": [10569], "characters": "\u2949" }, + "Ў": { "codepoints": [1038], "characters": "\u040E" }, + "Ŭ": { "codepoints": [364], "characters": "\u016C" }, + "Û": { "codepoints": [219], "characters": "\u00DB" }, + "Û": { "codepoints": [219], "characters": "\u00DB" }, + "У": { "codepoints": [1059], "characters": "\u0423" }, + "Ű": { "codepoints": [368], "characters": "\u0170" }, + "𝔘": { "codepoints": [120088], "characters": "\uD835\uDD18" }, + "Ù": { "codepoints": [217], "characters": "\u00D9" }, + "Ù": { "codepoints": [217], "characters": "\u00D9" }, + "Ū": { "codepoints": [362], "characters": "\u016A" }, + "_": { "codepoints": [95], "characters": "\u005F" }, + "⏟": { "codepoints": [9183], "characters": "\u23DF" }, + "⎵": { "codepoints": [9141], "characters": "\u23B5" }, + "⏝": { "codepoints": [9181], "characters": "\u23DD" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "⊎": { "codepoints": [8846], "characters": "\u228E" }, + "Ų": { "codepoints": [370], "characters": "\u0172" }, + "𝕌": { "codepoints": [120140], "characters": "\uD835\uDD4C" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "⤒": { "codepoints": [10514], "characters": "\u2912" }, + "⇅": { "codepoints": [8645], "characters": "\u21C5" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "⥮": { "codepoints": [10606], "characters": "\u296E" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "↥": { "codepoints": [8613], "characters": "\u21A5" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "ϒ": { "codepoints": [978], "characters": "\u03D2" }, + "Υ": { "codepoints": [933], "characters": "\u03A5" }, + "Ů": { "codepoints": [366], "characters": "\u016E" }, + "𝒰": { "codepoints": [119984], "characters": "\uD835\uDCB0" }, + "Ũ": { "codepoints": [360], "characters": "\u0168" }, + "Ü": { "codepoints": [220], "characters": "\u00DC" }, + "Ü": { "codepoints": [220], "characters": "\u00DC" }, + "⊫": { "codepoints": [8875], "characters": "\u22AB" }, + "⫫": { "codepoints": [10987], "characters": "\u2AEB" }, + "В": { "codepoints": [1042], "characters": "\u0412" }, + "⊩": { "codepoints": [8873], "characters": "\u22A9" }, + "⫦": { "codepoints": [10982], "characters": "\u2AE6" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "‖": { "codepoints": [8214], "characters": "\u2016" }, + "‖": { "codepoints": [8214], "characters": "\u2016" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "❘": { "codepoints": [10072], "characters": "\u2758" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + " ": { "codepoints": [8202], "characters": "\u200A" }, + "𝔙": { "codepoints": [120089], "characters": "\uD835\uDD19" }, + "𝕍": { "codepoints": [120141], "characters": "\uD835\uDD4D" }, + "𝒱": { "codepoints": [119985], "characters": "\uD835\uDCB1" }, + "⊪": { "codepoints": [8874], "characters": "\u22AA" }, + "Ŵ": { "codepoints": [372], "characters": "\u0174" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "𝔚": { "codepoints": [120090], "characters": "\uD835\uDD1A" }, + "𝕎": { "codepoints": [120142], "characters": "\uD835\uDD4E" }, + "𝒲": { "codepoints": [119986], "characters": "\uD835\uDCB2" }, + "𝔛": { "codepoints": [120091], "characters": "\uD835\uDD1B" }, + "Ξ": { "codepoints": [926], "characters": "\u039E" }, + "𝕏": { "codepoints": [120143], "characters": "\uD835\uDD4F" }, + "𝒳": { "codepoints": [119987], "characters": "\uD835\uDCB3" }, + "Я": { "codepoints": [1071], "characters": "\u042F" }, + "Ї": { "codepoints": [1031], "characters": "\u0407" }, + "Ю": { "codepoints": [1070], "characters": "\u042E" }, + "Ý": { "codepoints": [221], "characters": "\u00DD" }, + "Ý": { "codepoints": [221], "characters": "\u00DD" }, + "Ŷ": { "codepoints": [374], "characters": "\u0176" }, + "Ы": { "codepoints": [1067], "characters": "\u042B" }, + "𝔜": { "codepoints": [120092], "characters": "\uD835\uDD1C" }, + "𝕐": { "codepoints": [120144], "characters": "\uD835\uDD50" }, + "𝒴": { "codepoints": [119988], "characters": "\uD835\uDCB4" }, + "Ÿ": { "codepoints": [376], "characters": "\u0178" }, + "Ж": { "codepoints": [1046], "characters": "\u0416" }, + "Ź": { "codepoints": [377], "characters": "\u0179" }, + "Ž": { "codepoints": [381], "characters": "\u017D" }, + "З": { "codepoints": [1047], "characters": "\u0417" }, + "Ż": { "codepoints": [379], "characters": "\u017B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "Ζ": { "codepoints": [918], "characters": "\u0396" }, + "ℨ": { "codepoints": [8488], "characters": "\u2128" }, + "ℤ": { "codepoints": [8484], "characters": "\u2124" }, + "𝒵": { "codepoints": [119989], "characters": "\uD835\uDCB5" }, + "á": { "codepoints": [225], "characters": "\u00E1" }, + "á": { "codepoints": [225], "characters": "\u00E1" }, + "ă": { "codepoints": [259], "characters": "\u0103" }, + "∾": { "codepoints": [8766], "characters": "\u223E" }, + "∾̳": { "codepoints": [8766, 819], "characters": "\u223E\u0333" }, + "∿": { "codepoints": [8767], "characters": "\u223F" }, + "â": { "codepoints": [226], "characters": "\u00E2" }, + "â": { "codepoints": [226], "characters": "\u00E2" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "а": { "codepoints": [1072], "characters": "\u0430" }, + "æ": { "codepoints": [230], "characters": "\u00E6" }, + "æ": { "codepoints": [230], "characters": "\u00E6" }, + "⁡": { "codepoints": [8289], "characters": "\u2061" }, + "𝔞": { "codepoints": [120094], "characters": "\uD835\uDD1E" }, + "à": { "codepoints": [224], "characters": "\u00E0" }, + "à": { "codepoints": [224], "characters": "\u00E0" }, + "ℵ": { "codepoints": [8501], "characters": "\u2135" }, + "ℵ": { "codepoints": [8501], "characters": "\u2135" }, + "α": { "codepoints": [945], "characters": "\u03B1" }, + "ā": { "codepoints": [257], "characters": "\u0101" }, + "⨿": { "codepoints": [10815], "characters": "\u2A3F" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "∧": { "codepoints": [8743], "characters": "\u2227" }, + "⩕": { "codepoints": [10837], "characters": "\u2A55" }, + "⩜": { "codepoints": [10844], "characters": "\u2A5C" }, + "⩘": { "codepoints": [10840], "characters": "\u2A58" }, + "⩚": { "codepoints": [10842], "characters": "\u2A5A" }, + "∠": { "codepoints": [8736], "characters": "\u2220" }, + "⦤": { "codepoints": [10660], "characters": "\u29A4" }, + "∠": { "codepoints": [8736], "characters": "\u2220" }, + "∡": { "codepoints": [8737], "characters": "\u2221" }, + "⦨": { "codepoints": [10664], "characters": "\u29A8" }, + "⦩": { "codepoints": [10665], "characters": "\u29A9" }, + "⦪": { "codepoints": [10666], "characters": "\u29AA" }, + "⦫": { "codepoints": [10667], "characters": "\u29AB" }, + "⦬": { "codepoints": [10668], "characters": "\u29AC" }, + "⦭": { "codepoints": [10669], "characters": "\u29AD" }, + "⦮": { "codepoints": [10670], "characters": "\u29AE" }, + "⦯": { "codepoints": [10671], "characters": "\u29AF" }, + "∟": { "codepoints": [8735], "characters": "\u221F" }, + "⊾": { "codepoints": [8894], "characters": "\u22BE" }, + "⦝": { "codepoints": [10653], "characters": "\u299D" }, + "∢": { "codepoints": [8738], "characters": "\u2222" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "⍼": { "codepoints": [9084], "characters": "\u237C" }, + "ą": { "codepoints": [261], "characters": "\u0105" }, + "𝕒": { "codepoints": [120146], "characters": "\uD835\uDD52" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "⩰": { "codepoints": [10864], "characters": "\u2A70" }, + "⩯": { "codepoints": [10863], "characters": "\u2A6F" }, + "≊": { "codepoints": [8778], "characters": "\u224A" }, + "≋": { "codepoints": [8779], "characters": "\u224B" }, + "'": { "codepoints": [39], "characters": "\u0027" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "≊": { "codepoints": [8778], "characters": "\u224A" }, + "å": { "codepoints": [229], "characters": "\u00E5" }, + "å": { "codepoints": [229], "characters": "\u00E5" }, + "𝒶": { "codepoints": [119990], "characters": "\uD835\uDCB6" }, + "*": { "codepoints": [42], "characters": "\u002A" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "≍": { "codepoints": [8781], "characters": "\u224D" }, + "ã": { "codepoints": [227], "characters": "\u00E3" }, + "ã": { "codepoints": [227], "characters": "\u00E3" }, + "ä": { "codepoints": [228], "characters": "\u00E4" }, + "ä": { "codepoints": [228], "characters": "\u00E4" }, + "∳": { "codepoints": [8755], "characters": "\u2233" }, + "⨑": { "codepoints": [10769], "characters": "\u2A11" }, + "⫭": { "codepoints": [10989], "characters": "\u2AED" }, + "≌": { "codepoints": [8780], "characters": "\u224C" }, + "϶": { "codepoints": [1014], "characters": "\u03F6" }, + "‵": { "codepoints": [8245], "characters": "\u2035" }, + "∽": { "codepoints": [8765], "characters": "\u223D" }, + "⋍": { "codepoints": [8909], "characters": "\u22CD" }, + "⊽": { "codepoints": [8893], "characters": "\u22BD" }, + "⌅": { "codepoints": [8965], "characters": "\u2305" }, + "⌅": { "codepoints": [8965], "characters": "\u2305" }, + "⎵": { "codepoints": [9141], "characters": "\u23B5" }, + "⎶": { "codepoints": [9142], "characters": "\u23B6" }, + "≌": { "codepoints": [8780], "characters": "\u224C" }, + "б": { "codepoints": [1073], "characters": "\u0431" }, + "„": { "codepoints": [8222], "characters": "\u201E" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "⦰": { "codepoints": [10672], "characters": "\u29B0" }, + "϶": { "codepoints": [1014], "characters": "\u03F6" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "β": { "codepoints": [946], "characters": "\u03B2" }, + "ℶ": { "codepoints": [8502], "characters": "\u2136" }, + "≬": { "codepoints": [8812], "characters": "\u226C" }, + "𝔟": { "codepoints": [120095], "characters": "\uD835\uDD1F" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "◯": { "codepoints": [9711], "characters": "\u25EF" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "⨀": { "codepoints": [10752], "characters": "\u2A00" }, + "⨁": { "codepoints": [10753], "characters": "\u2A01" }, + "⨂": { "codepoints": [10754], "characters": "\u2A02" }, + "⨆": { "codepoints": [10758], "characters": "\u2A06" }, + "★": { "codepoints": [9733], "characters": "\u2605" }, + "▽": { "codepoints": [9661], "characters": "\u25BD" }, + "△": { "codepoints": [9651], "characters": "\u25B3" }, + "⨄": { "codepoints": [10756], "characters": "\u2A04" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "⤍": { "codepoints": [10509], "characters": "\u290D" }, + "⧫": { "codepoints": [10731], "characters": "\u29EB" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "▴": { "codepoints": [9652], "characters": "\u25B4" }, + "▾": { "codepoints": [9662], "characters": "\u25BE" }, + "◂": { "codepoints": [9666], "characters": "\u25C2" }, + "▸": { "codepoints": [9656], "characters": "\u25B8" }, + "␣": { "codepoints": [9251], "characters": "\u2423" }, + "▒": { "codepoints": [9618], "characters": "\u2592" }, + "░": { "codepoints": [9617], "characters": "\u2591" }, + "▓": { "codepoints": [9619], "characters": "\u2593" }, + "█": { "codepoints": [9608], "characters": "\u2588" }, + "=⃥": { "codepoints": [61, 8421], "characters": "\u003D\u20E5" }, + "≡⃥": { "codepoints": [8801, 8421], "characters": "\u2261\u20E5" }, + "⌐": { "codepoints": [8976], "characters": "\u2310" }, + "𝕓": { "codepoints": [120147], "characters": "\uD835\uDD53" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "⋈": { "codepoints": [8904], "characters": "\u22C8" }, + "╗": { "codepoints": [9559], "characters": "\u2557" }, + "╔": { "codepoints": [9556], "characters": "\u2554" }, + "╖": { "codepoints": [9558], "characters": "\u2556" }, + "╓": { "codepoints": [9555], "characters": "\u2553" }, + "═": { "codepoints": [9552], "characters": "\u2550" }, + "╦": { "codepoints": [9574], "characters": "\u2566" }, + "╩": { "codepoints": [9577], "characters": "\u2569" }, + "╤": { "codepoints": [9572], "characters": "\u2564" }, + "╧": { "codepoints": [9575], "characters": "\u2567" }, + "╝": { "codepoints": [9565], "characters": "\u255D" }, + "╚": { "codepoints": [9562], "characters": "\u255A" }, + "╜": { "codepoints": [9564], "characters": "\u255C" }, + "╙": { "codepoints": [9561], "characters": "\u2559" }, + "║": { "codepoints": [9553], "characters": "\u2551" }, + "╬": { "codepoints": [9580], "characters": "\u256C" }, + "╣": { "codepoints": [9571], "characters": "\u2563" }, + "╠": { "codepoints": [9568], "characters": "\u2560" }, + "╫": { "codepoints": [9579], "characters": "\u256B" }, + "╢": { "codepoints": [9570], "characters": "\u2562" }, + "╟": { "codepoints": [9567], "characters": "\u255F" }, + "⧉": { "codepoints": [10697], "characters": "\u29C9" }, + "╕": { "codepoints": [9557], "characters": "\u2555" }, + "╒": { "codepoints": [9554], "characters": "\u2552" }, + "┐": { "codepoints": [9488], "characters": "\u2510" }, + "┌": { "codepoints": [9484], "characters": "\u250C" }, + "─": { "codepoints": [9472], "characters": "\u2500" }, + "╥": { "codepoints": [9573], "characters": "\u2565" }, + "╨": { "codepoints": [9576], "characters": "\u2568" }, + "┬": { "codepoints": [9516], "characters": "\u252C" }, + "┴": { "codepoints": [9524], "characters": "\u2534" }, + "⊟": { "codepoints": [8863], "characters": "\u229F" }, + "⊞": { "codepoints": [8862], "characters": "\u229E" }, + "⊠": { "codepoints": [8864], "characters": "\u22A0" }, + "╛": { "codepoints": [9563], "characters": "\u255B" }, + "╘": { "codepoints": [9560], "characters": "\u2558" }, + "┘": { "codepoints": [9496], "characters": "\u2518" }, + "└": { "codepoints": [9492], "characters": "\u2514" }, + "│": { "codepoints": [9474], "characters": "\u2502" }, + "╪": { "codepoints": [9578], "characters": "\u256A" }, + "╡": { "codepoints": [9569], "characters": "\u2561" }, + "╞": { "codepoints": [9566], "characters": "\u255E" }, + "┼": { "codepoints": [9532], "characters": "\u253C" }, + "┤": { "codepoints": [9508], "characters": "\u2524" }, + "├": { "codepoints": [9500], "characters": "\u251C" }, + "‵": { "codepoints": [8245], "characters": "\u2035" }, + "˘": { "codepoints": [728], "characters": "\u02D8" }, + "¦": { "codepoints": [166], "characters": "\u00A6" }, + "¦": { "codepoints": [166], "characters": "\u00A6" }, + "𝒷": { "codepoints": [119991], "characters": "\uD835\uDCB7" }, + "⁏": { "codepoints": [8271], "characters": "\u204F" }, + "∽": { "codepoints": [8765], "characters": "\u223D" }, + "⋍": { "codepoints": [8909], "characters": "\u22CD" }, + "\": { "codepoints": [92], "characters": "\u005C" }, + "⧅": { "codepoints": [10693], "characters": "\u29C5" }, + "⟈": { "codepoints": [10184], "characters": "\u27C8" }, + "•": { "codepoints": [8226], "characters": "\u2022" }, + "•": { "codepoints": [8226], "characters": "\u2022" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "⪮": { "codepoints": [10926], "characters": "\u2AAE" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "ć": { "codepoints": [263], "characters": "\u0107" }, + "∩": { "codepoints": [8745], "characters": "\u2229" }, + "⩄": { "codepoints": [10820], "characters": "\u2A44" }, + "⩉": { "codepoints": [10825], "characters": "\u2A49" }, + "⩋": { "codepoints": [10827], "characters": "\u2A4B" }, + "⩇": { "codepoints": [10823], "characters": "\u2A47" }, + "⩀": { "codepoints": [10816], "characters": "\u2A40" }, + "∩︀": { "codepoints": [8745, 65024], "characters": "\u2229\uFE00" }, + "⁁": { "codepoints": [8257], "characters": "\u2041" }, + "ˇ": { "codepoints": [711], "characters": "\u02C7" }, + "⩍": { "codepoints": [10829], "characters": "\u2A4D" }, + "č": { "codepoints": [269], "characters": "\u010D" }, + "ç": { "codepoints": [231], "characters": "\u00E7" }, + "ç": { "codepoints": [231], "characters": "\u00E7" }, + "ĉ": { "codepoints": [265], "characters": "\u0109" }, + "⩌": { "codepoints": [10828], "characters": "\u2A4C" }, + "⩐": { "codepoints": [10832], "characters": "\u2A50" }, + "ċ": { "codepoints": [267], "characters": "\u010B" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "⦲": { "codepoints": [10674], "characters": "\u29B2" }, + "¢": { "codepoints": [162], "characters": "\u00A2" }, + "¢": { "codepoints": [162], "characters": "\u00A2" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "𝔠": { "codepoints": [120096], "characters": "\uD835\uDD20" }, + "ч": { "codepoints": [1095], "characters": "\u0447" }, + "✓": { "codepoints": [10003], "characters": "\u2713" }, + "✓": { "codepoints": [10003], "characters": "\u2713" }, + "χ": { "codepoints": [967], "characters": "\u03C7" }, + "○": { "codepoints": [9675], "characters": "\u25CB" }, + "⧃": { "codepoints": [10691], "characters": "\u29C3" }, + "ˆ": { "codepoints": [710], "characters": "\u02C6" }, + "≗": { "codepoints": [8791], "characters": "\u2257" }, + "↺": { "codepoints": [8634], "characters": "\u21BA" }, + "↻": { "codepoints": [8635], "characters": "\u21BB" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, + "⊛": { "codepoints": [8859], "characters": "\u229B" }, + "⊚": { "codepoints": [8858], "characters": "\u229A" }, + "⊝": { "codepoints": [8861], "characters": "\u229D" }, + "≗": { "codepoints": [8791], "characters": "\u2257" }, + "⨐": { "codepoints": [10768], "characters": "\u2A10" }, + "⫯": { "codepoints": [10991], "characters": "\u2AEF" }, + "⧂": { "codepoints": [10690], "characters": "\u29C2" }, + "♣": { "codepoints": [9827], "characters": "\u2663" }, + "♣": { "codepoints": [9827], "characters": "\u2663" }, + ":": { "codepoints": [58], "characters": "\u003A" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + ",": { "codepoints": [44], "characters": "\u002C" }, + "@": { "codepoints": [64], "characters": "\u0040" }, + "∁": { "codepoints": [8705], "characters": "\u2201" }, + "∘": { "codepoints": [8728], "characters": "\u2218" }, + "∁": { "codepoints": [8705], "characters": "\u2201" }, + "ℂ": { "codepoints": [8450], "characters": "\u2102" }, + "≅": { "codepoints": [8773], "characters": "\u2245" }, + "⩭": { "codepoints": [10861], "characters": "\u2A6D" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "𝕔": { "codepoints": [120148], "characters": "\uD835\uDD54" }, + "∐": { "codepoints": [8720], "characters": "\u2210" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "℗": { "codepoints": [8471], "characters": "\u2117" }, + "↵": { "codepoints": [8629], "characters": "\u21B5" }, + "✗": { "codepoints": [10007], "characters": "\u2717" }, + "𝒸": { "codepoints": [119992], "characters": "\uD835\uDCB8" }, + "⫏": { "codepoints": [10959], "characters": "\u2ACF" }, + "⫑": { "codepoints": [10961], "characters": "\u2AD1" }, + "⫐": { "codepoints": [10960], "characters": "\u2AD0" }, + "⫒": { "codepoints": [10962], "characters": "\u2AD2" }, + "⋯": { "codepoints": [8943], "characters": "\u22EF" }, + "⤸": { "codepoints": [10552], "characters": "\u2938" }, + "⤵": { "codepoints": [10549], "characters": "\u2935" }, + "⋞": { "codepoints": [8926], "characters": "\u22DE" }, + "⋟": { "codepoints": [8927], "characters": "\u22DF" }, + "↶": { "codepoints": [8630], "characters": "\u21B6" }, + "⤽": { "codepoints": [10557], "characters": "\u293D" }, + "∪": { "codepoints": [8746], "characters": "\u222A" }, + "⩈": { "codepoints": [10824], "characters": "\u2A48" }, + "⩆": { "codepoints": [10822], "characters": "\u2A46" }, + "⩊": { "codepoints": [10826], "characters": "\u2A4A" }, + "⊍": { "codepoints": [8845], "characters": "\u228D" }, + "⩅": { "codepoints": [10821], "characters": "\u2A45" }, + "∪︀": { "codepoints": [8746, 65024], "characters": "\u222A\uFE00" }, + "↷": { "codepoints": [8631], "characters": "\u21B7" }, + "⤼": { "codepoints": [10556], "characters": "\u293C" }, + "⋞": { "codepoints": [8926], "characters": "\u22DE" }, + "⋟": { "codepoints": [8927], "characters": "\u22DF" }, + "⋎": { "codepoints": [8910], "characters": "\u22CE" }, + "⋏": { "codepoints": [8911], "characters": "\u22CF" }, + "¤": { "codepoints": [164], "characters": "\u00A4" }, + "¤": { "codepoints": [164], "characters": "\u00A4" }, + "↶": { "codepoints": [8630], "characters": "\u21B6" }, + "↷": { "codepoints": [8631], "characters": "\u21B7" }, + "⋎": { "codepoints": [8910], "characters": "\u22CE" }, + "⋏": { "codepoints": [8911], "characters": "\u22CF" }, + "∲": { "codepoints": [8754], "characters": "\u2232" }, + "∱": { "codepoints": [8753], "characters": "\u2231" }, + "⌭": { "codepoints": [9005], "characters": "\u232D" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "⥥": { "codepoints": [10597], "characters": "\u2965" }, + "†": { "codepoints": [8224], "characters": "\u2020" }, + "ℸ": { "codepoints": [8504], "characters": "\u2138" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "‐": { "codepoints": [8208], "characters": "\u2010" }, + "⊣": { "codepoints": [8867], "characters": "\u22A3" }, + "⤏": { "codepoints": [10511], "characters": "\u290F" }, + "˝": { "codepoints": [733], "characters": "\u02DD" }, + "ď": { "codepoints": [271], "characters": "\u010F" }, + "д": { "codepoints": [1076], "characters": "\u0434" }, + "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, + "‡": { "codepoints": [8225], "characters": "\u2021" }, + "⇊": { "codepoints": [8650], "characters": "\u21CA" }, + "⩷": { "codepoints": [10871], "characters": "\u2A77" }, + "°": { "codepoints": [176], "characters": "\u00B0" }, + "°": { "codepoints": [176], "characters": "\u00B0" }, + "δ": { "codepoints": [948], "characters": "\u03B4" }, + "⦱": { "codepoints": [10673], "characters": "\u29B1" }, + "⥿": { "codepoints": [10623], "characters": "\u297F" }, + "𝔡": { "codepoints": [120097], "characters": "\uD835\uDD21" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "♦": { "codepoints": [9830], "characters": "\u2666" }, + "♦": { "codepoints": [9830], "characters": "\u2666" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "ϝ": { "codepoints": [989], "characters": "\u03DD" }, + "⋲": { "codepoints": [8946], "characters": "\u22F2" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "⋇": { "codepoints": [8903], "characters": "\u22C7" }, + "⋇": { "codepoints": [8903], "characters": "\u22C7" }, + "ђ": { "codepoints": [1106], "characters": "\u0452" }, + "⌞": { "codepoints": [8990], "characters": "\u231E" }, + "⌍": { "codepoints": [8973], "characters": "\u230D" }, + "$": { "codepoints": [36], "characters": "\u0024" }, + "𝕕": { "codepoints": [120149], "characters": "\uD835\uDD55" }, + "˙": { "codepoints": [729], "characters": "\u02D9" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "≑": { "codepoints": [8785], "characters": "\u2251" }, + "∸": { "codepoints": [8760], "characters": "\u2238" }, + "∔": { "codepoints": [8724], "characters": "\u2214" }, + "⊡": { "codepoints": [8865], "characters": "\u22A1" }, + "⌆": { "codepoints": [8966], "characters": "\u2306" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "⇊": { "codepoints": [8650], "characters": "\u21CA" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⤐": { "codepoints": [10512], "characters": "\u2910" }, + "⌟": { "codepoints": [8991], "characters": "\u231F" }, + "⌌": { "codepoints": [8972], "characters": "\u230C" }, + "𝒹": { "codepoints": [119993], "characters": "\uD835\uDCB9" }, + "ѕ": { "codepoints": [1109], "characters": "\u0455" }, + "⧶": { "codepoints": [10742], "characters": "\u29F6" }, + "đ": { "codepoints": [273], "characters": "\u0111" }, + "⋱": { "codepoints": [8945], "characters": "\u22F1" }, + "▿": { "codepoints": [9663], "characters": "\u25BF" }, + "▾": { "codepoints": [9662], "characters": "\u25BE" }, + "⇵": { "codepoints": [8693], "characters": "\u21F5" }, + "⥯": { "codepoints": [10607], "characters": "\u296F" }, + "⦦": { "codepoints": [10662], "characters": "\u29A6" }, + "џ": { "codepoints": [1119], "characters": "\u045F" }, + "⟿": { "codepoints": [10239], "characters": "\u27FF" }, + "⩷": { "codepoints": [10871], "characters": "\u2A77" }, + "≑": { "codepoints": [8785], "characters": "\u2251" }, + "é": { "codepoints": [233], "characters": "\u00E9" }, + "é": { "codepoints": [233], "characters": "\u00E9" }, + "⩮": { "codepoints": [10862], "characters": "\u2A6E" }, + "ě": { "codepoints": [283], "characters": "\u011B" }, + "≖": { "codepoints": [8790], "characters": "\u2256" }, + "ê": { "codepoints": [234], "characters": "\u00EA" }, + "ê": { "codepoints": [234], "characters": "\u00EA" }, + "≕": { "codepoints": [8789], "characters": "\u2255" }, + "э": { "codepoints": [1101], "characters": "\u044D" }, + "ė": { "codepoints": [279], "characters": "\u0117" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "≒": { "codepoints": [8786], "characters": "\u2252" }, + "𝔢": { "codepoints": [120098], "characters": "\uD835\uDD22" }, + "⪚": { "codepoints": [10906], "characters": "\u2A9A" }, + "è": { "codepoints": [232], "characters": "\u00E8" }, + "è": { "codepoints": [232], "characters": "\u00E8" }, + "⪖": { "codepoints": [10902], "characters": "\u2A96" }, + "⪘": { "codepoints": [10904], "characters": "\u2A98" }, + "⪙": { "codepoints": [10905], "characters": "\u2A99" }, + "⏧": { "codepoints": [9191], "characters": "\u23E7" }, + "ℓ": { "codepoints": [8467], "characters": "\u2113" }, + "⪕": { "codepoints": [10901], "characters": "\u2A95" }, + "⪗": { "codepoints": [10903], "characters": "\u2A97" }, + "ē": { "codepoints": [275], "characters": "\u0113" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + " ": { "codepoints": [8196], "characters": "\u2004" }, + " ": { "codepoints": [8197], "characters": "\u2005" }, + " ": { "codepoints": [8195], "characters": "\u2003" }, + "ŋ": { "codepoints": [331], "characters": "\u014B" }, + " ": { "codepoints": [8194], "characters": "\u2002" }, + "ę": { "codepoints": [281], "characters": "\u0119" }, + "𝕖": { "codepoints": [120150], "characters": "\uD835\uDD56" }, + "⋕": { "codepoints": [8917], "characters": "\u22D5" }, + "⧣": { "codepoints": [10723], "characters": "\u29E3" }, + "⩱": { "codepoints": [10865], "characters": "\u2A71" }, + "ε": { "codepoints": [949], "characters": "\u03B5" }, + "ε": { "codepoints": [949], "characters": "\u03B5" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "≖": { "codepoints": [8790], "characters": "\u2256" }, + "≕": { "codepoints": [8789], "characters": "\u2255" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "⪖": { "codepoints": [10902], "characters": "\u2A96" }, + "⪕": { "codepoints": [10901], "characters": "\u2A95" }, + "=": { "codepoints": [61], "characters": "\u003D" }, + "≟": { "codepoints": [8799], "characters": "\u225F" }, + "≡": { "codepoints": [8801], "characters": "\u2261" }, + "⩸": { "codepoints": [10872], "characters": "\u2A78" }, + "⧥": { "codepoints": [10725], "characters": "\u29E5" }, + "≓": { "codepoints": [8787], "characters": "\u2253" }, + "⥱": { "codepoints": [10609], "characters": "\u2971" }, + "ℯ": { "codepoints": [8495], "characters": "\u212F" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "η": { "codepoints": [951], "characters": "\u03B7" }, + "ð": { "codepoints": [240], "characters": "\u00F0" }, + "ð": { "codepoints": [240], "characters": "\u00F0" }, + "ë": { "codepoints": [235], "characters": "\u00EB" }, + "ë": { "codepoints": [235], "characters": "\u00EB" }, + "€": { "codepoints": [8364], "characters": "\u20AC" }, + "!": { "codepoints": [33], "characters": "\u0021" }, + "∃": { "codepoints": [8707], "characters": "\u2203" }, + "ℰ": { "codepoints": [8496], "characters": "\u2130" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "≒": { "codepoints": [8786], "characters": "\u2252" }, + "ф": { "codepoints": [1092], "characters": "\u0444" }, + "♀": { "codepoints": [9792], "characters": "\u2640" }, + "ffi": { "codepoints": [64259], "characters": "\uFB03" }, + "ff": { "codepoints": [64256], "characters": "\uFB00" }, + "ffl": { "codepoints": [64260], "characters": "\uFB04" }, + "𝔣": { "codepoints": [120099], "characters": "\uD835\uDD23" }, + "fi": { "codepoints": [64257], "characters": "\uFB01" }, + "fj": { "codepoints": [102, 106], "characters": "\u0066\u006A" }, + "♭": { "codepoints": [9837], "characters": "\u266D" }, + "fl": { "codepoints": [64258], "characters": "\uFB02" }, + "▱": { "codepoints": [9649], "characters": "\u25B1" }, + "ƒ": { "codepoints": [402], "characters": "\u0192" }, + "𝕗": { "codepoints": [120151], "characters": "\uD835\uDD57" }, + "∀": { "codepoints": [8704], "characters": "\u2200" }, + "⋔": { "codepoints": [8916], "characters": "\u22D4" }, + "⫙": { "codepoints": [10969], "characters": "\u2AD9" }, + "⨍": { "codepoints": [10765], "characters": "\u2A0D" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "⅓": { "codepoints": [8531], "characters": "\u2153" }, + "¼": { "codepoints": [188], "characters": "\u00BC" }, + "¼": { "codepoints": [188], "characters": "\u00BC" }, + "⅕": { "codepoints": [8533], "characters": "\u2155" }, + "⅙": { "codepoints": [8537], "characters": "\u2159" }, + "⅛": { "codepoints": [8539], "characters": "\u215B" }, + "⅔": { "codepoints": [8532], "characters": "\u2154" }, + "⅖": { "codepoints": [8534], "characters": "\u2156" }, + "¾": { "codepoints": [190], "characters": "\u00BE" }, + "¾": { "codepoints": [190], "characters": "\u00BE" }, + "⅗": { "codepoints": [8535], "characters": "\u2157" }, + "⅜": { "codepoints": [8540], "characters": "\u215C" }, + "⅘": { "codepoints": [8536], "characters": "\u2158" }, + "⅚": { "codepoints": [8538], "characters": "\u215A" }, + "⅝": { "codepoints": [8541], "characters": "\u215D" }, + "⅞": { "codepoints": [8542], "characters": "\u215E" }, + "⁄": { "codepoints": [8260], "characters": "\u2044" }, + "⌢": { "codepoints": [8994], "characters": "\u2322" }, + "𝒻": { "codepoints": [119995], "characters": "\uD835\uDCBB" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, + "ǵ": { "codepoints": [501], "characters": "\u01F5" }, + "γ": { "codepoints": [947], "characters": "\u03B3" }, + "ϝ": { "codepoints": [989], "characters": "\u03DD" }, + "⪆": { "codepoints": [10886], "characters": "\u2A86" }, + "ğ": { "codepoints": [287], "characters": "\u011F" }, + "ĝ": { "codepoints": [285], "characters": "\u011D" }, + "г": { "codepoints": [1075], "characters": "\u0433" }, + "ġ": { "codepoints": [289], "characters": "\u0121" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "⪩": { "codepoints": [10921], "characters": "\u2AA9" }, + "⪀": { "codepoints": [10880], "characters": "\u2A80" }, + "⪂": { "codepoints": [10882], "characters": "\u2A82" }, + "⪄": { "codepoints": [10884], "characters": "\u2A84" }, + "⋛︀": { "codepoints": [8923, 65024], "characters": "\u22DB\uFE00" }, + "⪔": { "codepoints": [10900], "characters": "\u2A94" }, + "𝔤": { "codepoints": [120100], "characters": "\uD835\uDD24" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "⋙": { "codepoints": [8921], "characters": "\u22D9" }, + "ℷ": { "codepoints": [8503], "characters": "\u2137" }, + "ѓ": { "codepoints": [1107], "characters": "\u0453" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "⪒": { "codepoints": [10898], "characters": "\u2A92" }, + "⪥": { "codepoints": [10917], "characters": "\u2AA5" }, + "⪤": { "codepoints": [10916], "characters": "\u2AA4" }, + "≩": { "codepoints": [8809], "characters": "\u2269" }, + "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, + "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, + "⪈": { "codepoints": [10888], "characters": "\u2A88" }, + "⪈": { "codepoints": [10888], "characters": "\u2A88" }, + "≩": { "codepoints": [8809], "characters": "\u2269" }, + "⋧": { "codepoints": [8935], "characters": "\u22E7" }, + "𝕘": { "codepoints": [120152], "characters": "\uD835\uDD58" }, + "`": { "codepoints": [96], "characters": "\u0060" }, + "ℊ": { "codepoints": [8458], "characters": "\u210A" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "⪎": { "codepoints": [10894], "characters": "\u2A8E" }, + "⪐": { "codepoints": [10896], "characters": "\u2A90" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + "⪧": { "codepoints": [10919], "characters": "\u2AA7" }, + "⩺": { "codepoints": [10874], "characters": "\u2A7A" }, + "⋗": { "codepoints": [8919], "characters": "\u22D7" }, + "⦕": { "codepoints": [10645], "characters": "\u2995" }, + "⩼": { "codepoints": [10876], "characters": "\u2A7C" }, + "⪆": { "codepoints": [10886], "characters": "\u2A86" }, + "⥸": { "codepoints": [10616], "characters": "\u2978" }, + "⋗": { "codepoints": [8919], "characters": "\u22D7" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, + "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + " ": { "codepoints": [8202], "characters": "\u200A" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "ъ": { "codepoints": [1098], "characters": "\u044A" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⥈": { "codepoints": [10568], "characters": "\u2948" }, + "↭": { "codepoints": [8621], "characters": "\u21AD" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ĥ": { "codepoints": [293], "characters": "\u0125" }, + "♥": { "codepoints": [9829], "characters": "\u2665" }, + "♥": { "codepoints": [9829], "characters": "\u2665" }, + "…": { "codepoints": [8230], "characters": "\u2026" }, + "⊹": { "codepoints": [8889], "characters": "\u22B9" }, + "𝔥": { "codepoints": [120101], "characters": "\uD835\uDD25" }, + "⤥": { "codepoints": [10533], "characters": "\u2925" }, + "⤦": { "codepoints": [10534], "characters": "\u2926" }, + "⇿": { "codepoints": [8703], "characters": "\u21FF" }, + "∻": { "codepoints": [8763], "characters": "\u223B" }, + "↩": { "codepoints": [8617], "characters": "\u21A9" }, + "↪": { "codepoints": [8618], "characters": "\u21AA" }, + "𝕙": { "codepoints": [120153], "characters": "\uD835\uDD59" }, + "―": { "codepoints": [8213], "characters": "\u2015" }, + "𝒽": { "codepoints": [119997], "characters": "\uD835\uDCBD" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ħ": { "codepoints": [295], "characters": "\u0127" }, + "⁃": { "codepoints": [8259], "characters": "\u2043" }, + "‐": { "codepoints": [8208], "characters": "\u2010" }, + "í": { "codepoints": [237], "characters": "\u00ED" }, + "í": { "codepoints": [237], "characters": "\u00ED" }, + "⁣": { "codepoints": [8291], "characters": "\u2063" }, + "î": { "codepoints": [238], "characters": "\u00EE" }, + "î": { "codepoints": [238], "characters": "\u00EE" }, + "и": { "codepoints": [1080], "characters": "\u0438" }, + "е": { "codepoints": [1077], "characters": "\u0435" }, + "¡": { "codepoints": [161], "characters": "\u00A1" }, + "¡": { "codepoints": [161], "characters": "\u00A1" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "𝔦": { "codepoints": [120102], "characters": "\uD835\uDD26" }, + "ì": { "codepoints": [236], "characters": "\u00EC" }, + "ì": { "codepoints": [236], "characters": "\u00EC" }, + "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, + "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, + "∭": { "codepoints": [8749], "characters": "\u222D" }, + "⧜": { "codepoints": [10716], "characters": "\u29DC" }, + "℩": { "codepoints": [8489], "characters": "\u2129" }, + "ij": { "codepoints": [307], "characters": "\u0133" }, + "ī": { "codepoints": [299], "characters": "\u012B" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "ℐ": { "codepoints": [8464], "characters": "\u2110" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "ı": { "codepoints": [305], "characters": "\u0131" }, + "⊷": { "codepoints": [8887], "characters": "\u22B7" }, + "Ƶ": { "codepoints": [437], "characters": "\u01B5" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "℅": { "codepoints": [8453], "characters": "\u2105" }, + "∞": { "codepoints": [8734], "characters": "\u221E" }, + "⧝": { "codepoints": [10717], "characters": "\u29DD" }, + "ı": { "codepoints": [305], "characters": "\u0131" }, + "∫": { "codepoints": [8747], "characters": "\u222B" }, + "⊺": { "codepoints": [8890], "characters": "\u22BA" }, + "ℤ": { "codepoints": [8484], "characters": "\u2124" }, + "⊺": { "codepoints": [8890], "characters": "\u22BA" }, + "⨗": { "codepoints": [10775], "characters": "\u2A17" }, + "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, + "ё": { "codepoints": [1105], "characters": "\u0451" }, + "į": { "codepoints": [303], "characters": "\u012F" }, + "𝕚": { "codepoints": [120154], "characters": "\uD835\uDD5A" }, + "ι": { "codepoints": [953], "characters": "\u03B9" }, + "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, + "¿": { "codepoints": [191], "characters": "\u00BF" }, + "¿": { "codepoints": [191], "characters": "\u00BF" }, + "𝒾": { "codepoints": [119998], "characters": "\uD835\uDCBE" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "⋹": { "codepoints": [8953], "characters": "\u22F9" }, + "⋵": { "codepoints": [8949], "characters": "\u22F5" }, + "⋴": { "codepoints": [8948], "characters": "\u22F4" }, + "⋳": { "codepoints": [8947], "characters": "\u22F3" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "⁢": { "codepoints": [8290], "characters": "\u2062" }, + "ĩ": { "codepoints": [297], "characters": "\u0129" }, + "і": { "codepoints": [1110], "characters": "\u0456" }, + "ï": { "codepoints": [239], "characters": "\u00EF" }, + "ï": { "codepoints": [239], "characters": "\u00EF" }, + "ĵ": { "codepoints": [309], "characters": "\u0135" }, + "й": { "codepoints": [1081], "characters": "\u0439" }, + "𝔧": { "codepoints": [120103], "characters": "\uD835\uDD27" }, + "ȷ": { "codepoints": [567], "characters": "\u0237" }, + "𝕛": { "codepoints": [120155], "characters": "\uD835\uDD5B" }, + "𝒿": { "codepoints": [119999], "characters": "\uD835\uDCBF" }, + "ј": { "codepoints": [1112], "characters": "\u0458" }, + "є": { "codepoints": [1108], "characters": "\u0454" }, + "κ": { "codepoints": [954], "characters": "\u03BA" }, + "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, + "ķ": { "codepoints": [311], "characters": "\u0137" }, + "к": { "codepoints": [1082], "characters": "\u043A" }, + "𝔨": { "codepoints": [120104], "characters": "\uD835\uDD28" }, + "ĸ": { "codepoints": [312], "characters": "\u0138" }, + "х": { "codepoints": [1093], "characters": "\u0445" }, + "ќ": { "codepoints": [1116], "characters": "\u045C" }, + "𝕜": { "codepoints": [120156], "characters": "\uD835\uDD5C" }, + "𝓀": { "codepoints": [120000], "characters": "\uD835\uDCC0" }, + "⇚": { "codepoints": [8666], "characters": "\u21DA" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⤛": { "codepoints": [10523], "characters": "\u291B" }, + "⤎": { "codepoints": [10510], "characters": "\u290E" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, + "⥢": { "codepoints": [10594], "characters": "\u2962" }, + "ĺ": { "codepoints": [314], "characters": "\u013A" }, + "⦴": { "codepoints": [10676], "characters": "\u29B4" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "λ": { "codepoints": [955], "characters": "\u03BB" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "⦑": { "codepoints": [10641], "characters": "\u2991" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "⪅": { "codepoints": [10885], "characters": "\u2A85" }, + "«": { "codepoints": [171], "characters": "\u00AB" }, + "«": { "codepoints": [171], "characters": "\u00AB" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "⇤": { "codepoints": [8676], "characters": "\u21E4" }, + "⤟": { "codepoints": [10527], "characters": "\u291F" }, + "⤝": { "codepoints": [10525], "characters": "\u291D" }, + "↩": { "codepoints": [8617], "characters": "\u21A9" }, + "↫": { "codepoints": [8619], "characters": "\u21AB" }, + "⤹": { "codepoints": [10553], "characters": "\u2939" }, + "⥳": { "codepoints": [10611], "characters": "\u2973" }, + "↢": { "codepoints": [8610], "characters": "\u21A2" }, + "⪫": { "codepoints": [10923], "characters": "\u2AAB" }, + "⤙": { "codepoints": [10521], "characters": "\u2919" }, + "⪭": { "codepoints": [10925], "characters": "\u2AAD" }, + "⪭︀": { "codepoints": [10925, 65024], "characters": "\u2AAD\uFE00" }, + "⤌": { "codepoints": [10508], "characters": "\u290C" }, + "❲": { "codepoints": [10098], "characters": "\u2772" }, + "{": { "codepoints": [123], "characters": "\u007B" }, + "[": { "codepoints": [91], "characters": "\u005B" }, + "⦋": { "codepoints": [10635], "characters": "\u298B" }, + "⦏": { "codepoints": [10639], "characters": "\u298F" }, + "⦍": { "codepoints": [10637], "characters": "\u298D" }, + "ľ": { "codepoints": [318], "characters": "\u013E" }, + "ļ": { "codepoints": [316], "characters": "\u013C" }, + "⌈": { "codepoints": [8968], "characters": "\u2308" }, + "{": { "codepoints": [123], "characters": "\u007B" }, + "л": { "codepoints": [1083], "characters": "\u043B" }, + "⤶": { "codepoints": [10550], "characters": "\u2936" }, + "“": { "codepoints": [8220], "characters": "\u201C" }, + "„": { "codepoints": [8222], "characters": "\u201E" }, + "⥧": { "codepoints": [10599], "characters": "\u2967" }, + "⥋": { "codepoints": [10571], "characters": "\u294B" }, + "↲": { "codepoints": [8626], "characters": "\u21B2" }, + "≤": { "codepoints": [8804], "characters": "\u2264" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "↢": { "codepoints": [8610], "characters": "\u21A2" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⇇": { "codepoints": [8647], "characters": "\u21C7" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "↭": { "codepoints": [8621], "characters": "\u21AD" }, + "⋋": { "codepoints": [8907], "characters": "\u22CB" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "≤": { "codepoints": [8804], "characters": "\u2264" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "⪨": { "codepoints": [10920], "characters": "\u2AA8" }, + "⩿": { "codepoints": [10879], "characters": "\u2A7F" }, + "⪁": { "codepoints": [10881], "characters": "\u2A81" }, + "⪃": { "codepoints": [10883], "characters": "\u2A83" }, + "⋚︀": { "codepoints": [8922, 65024], "characters": "\u22DA\uFE00" }, + "⪓": { "codepoints": [10899], "characters": "\u2A93" }, + "⪅": { "codepoints": [10885], "characters": "\u2A85" }, + "⋖": { "codepoints": [8918], "characters": "\u22D6" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "⥼": { "codepoints": [10620], "characters": "\u297C" }, + "⌊": { "codepoints": [8970], "characters": "\u230A" }, + "𝔩": { "codepoints": [120105], "characters": "\uD835\uDD29" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "⪑": { "codepoints": [10897], "characters": "\u2A91" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⥪": { "codepoints": [10602], "characters": "\u296A" }, + "▄": { "codepoints": [9604], "characters": "\u2584" }, + "љ": { "codepoints": [1113], "characters": "\u0459" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + "⇇": { "codepoints": [8647], "characters": "\u21C7" }, + "⌞": { "codepoints": [8990], "characters": "\u231E" }, + "⥫": { "codepoints": [10603], "characters": "\u296B" }, + "◺": { "codepoints": [9722], "characters": "\u25FA" }, + "ŀ": { "codepoints": [320], "characters": "\u0140" }, + "⎰": { "codepoints": [9136], "characters": "\u23B0" }, + "⎰": { "codepoints": [9136], "characters": "\u23B0" }, + "≨": { "codepoints": [8808], "characters": "\u2268" }, + "⪉": { "codepoints": [10889], "characters": "\u2A89" }, + "⪉": { "codepoints": [10889], "characters": "\u2A89" }, + "⪇": { "codepoints": [10887], "characters": "\u2A87" }, + "⪇": { "codepoints": [10887], "characters": "\u2A87" }, + "≨": { "codepoints": [8808], "characters": "\u2268" }, + "⋦": { "codepoints": [8934], "characters": "\u22E6" }, + "⟬": { "codepoints": [10220], "characters": "\u27EC" }, + "⇽": { "codepoints": [8701], "characters": "\u21FD" }, + "⟦": { "codepoints": [10214], "characters": "\u27E6" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "⟼": { "codepoints": [10236], "characters": "\u27FC" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "↫": { "codepoints": [8619], "characters": "\u21AB" }, + "↬": { "codepoints": [8620], "characters": "\u21AC" }, + "⦅": { "codepoints": [10629], "characters": "\u2985" }, + "𝕝": { "codepoints": [120157], "characters": "\uD835\uDD5D" }, + "⨭": { "codepoints": [10797], "characters": "\u2A2D" }, + "⨴": { "codepoints": [10804], "characters": "\u2A34" }, + "∗": { "codepoints": [8727], "characters": "\u2217" }, + "_": { "codepoints": [95], "characters": "\u005F" }, + "◊": { "codepoints": [9674], "characters": "\u25CA" }, + "◊": { "codepoints": [9674], "characters": "\u25CA" }, + "⧫": { "codepoints": [10731], "characters": "\u29EB" }, + "(": { "codepoints": [40], "characters": "\u0028" }, + "⦓": { "codepoints": [10643], "characters": "\u2993" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⌟": { "codepoints": [8991], "characters": "\u231F" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "⥭": { "codepoints": [10605], "characters": "\u296D" }, + "‎": { "codepoints": [8206], "characters": "\u200E" }, + "⊿": { "codepoints": [8895], "characters": "\u22BF" }, + "‹": { "codepoints": [8249], "characters": "\u2039" }, + "𝓁": { "codepoints": [120001], "characters": "\uD835\uDCC1" }, + "↰": { "codepoints": [8624], "characters": "\u21B0" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "⪍": { "codepoints": [10893], "characters": "\u2A8D" }, + "⪏": { "codepoints": [10895], "characters": "\u2A8F" }, + "[": { "codepoints": [91], "characters": "\u005B" }, + "‘": { "codepoints": [8216], "characters": "\u2018" }, + "‚": { "codepoints": [8218], "characters": "\u201A" }, + "ł": { "codepoints": [322], "characters": "\u0142" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "⪦": { "codepoints": [10918], "characters": "\u2AA6" }, + "⩹": { "codepoints": [10873], "characters": "\u2A79" }, + "⋖": { "codepoints": [8918], "characters": "\u22D6" }, + "⋋": { "codepoints": [8907], "characters": "\u22CB" }, + "⋉": { "codepoints": [8905], "characters": "\u22C9" }, + "⥶": { "codepoints": [10614], "characters": "\u2976" }, + "⩻": { "codepoints": [10875], "characters": "\u2A7B" }, + "⦖": { "codepoints": [10646], "characters": "\u2996" }, + "◃": { "codepoints": [9667], "characters": "\u25C3" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "◂": { "codepoints": [9666], "characters": "\u25C2" }, + "⥊": { "codepoints": [10570], "characters": "\u294A" }, + "⥦": { "codepoints": [10598], "characters": "\u2966" }, + "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, + "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, + "∺": { "codepoints": [8762], "characters": "\u223A" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "♂": { "codepoints": [9794], "characters": "\u2642" }, + "✠": { "codepoints": [10016], "characters": "\u2720" }, + "✠": { "codepoints": [10016], "characters": "\u2720" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "↧": { "codepoints": [8615], "characters": "\u21A7" }, + "↤": { "codepoints": [8612], "characters": "\u21A4" }, + "↥": { "codepoints": [8613], "characters": "\u21A5" }, + "▮": { "codepoints": [9646], "characters": "\u25AE" }, + "⨩": { "codepoints": [10793], "characters": "\u2A29" }, + "м": { "codepoints": [1084], "characters": "\u043C" }, + "—": { "codepoints": [8212], "characters": "\u2014" }, + "∡": { "codepoints": [8737], "characters": "\u2221" }, + "𝔪": { "codepoints": [120106], "characters": "\uD835\uDD2A" }, + "℧": { "codepoints": [8487], "characters": "\u2127" }, + "µ": { "codepoints": [181], "characters": "\u00B5" }, + "µ": { "codepoints": [181], "characters": "\u00B5" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "*": { "codepoints": [42], "characters": "\u002A" }, + "⫰": { "codepoints": [10992], "characters": "\u2AF0" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "−": { "codepoints": [8722], "characters": "\u2212" }, + "⊟": { "codepoints": [8863], "characters": "\u229F" }, + "∸": { "codepoints": [8760], "characters": "\u2238" }, + "⨪": { "codepoints": [10794], "characters": "\u2A2A" }, + "⫛": { "codepoints": [10971], "characters": "\u2ADB" }, + "…": { "codepoints": [8230], "characters": "\u2026" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "⊧": { "codepoints": [8871], "characters": "\u22A7" }, + "𝕞": { "codepoints": [120158], "characters": "\uD835\uDD5E" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "𝓂": { "codepoints": [120002], "characters": "\uD835\uDCC2" }, + "∾": { "codepoints": [8766], "characters": "\u223E" }, + "μ": { "codepoints": [956], "characters": "\u03BC" }, + "⊸": { "codepoints": [8888], "characters": "\u22B8" }, + "⊸": { "codepoints": [8888], "characters": "\u22B8" }, + "⋙̸": { "codepoints": [8921, 824], "characters": "\u22D9\u0338" }, + "≫⃒": { "codepoints": [8811, 8402], "characters": "\u226B\u20D2" }, + "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, + "⇍": { "codepoints": [8653], "characters": "\u21CD" }, + "⇎": { "codepoints": [8654], "characters": "\u21CE" }, + "⋘̸": { "codepoints": [8920, 824], "characters": "\u22D8\u0338" }, + "≪⃒": { "codepoints": [8810, 8402], "characters": "\u226A\u20D2" }, + "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, + "⇏": { "codepoints": [8655], "characters": "\u21CF" }, + "⊯": { "codepoints": [8879], "characters": "\u22AF" }, + "⊮": { "codepoints": [8878], "characters": "\u22AE" }, + "∇": { "codepoints": [8711], "characters": "\u2207" }, + "ń": { "codepoints": [324], "characters": "\u0144" }, + "∠⃒": { "codepoints": [8736, 8402], "characters": "\u2220\u20D2" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "⩰̸": { "codepoints": [10864, 824], "characters": "\u2A70\u0338" }, + "≋̸": { "codepoints": [8779, 824], "characters": "\u224B\u0338" }, + "ʼn": { "codepoints": [329], "characters": "\u0149" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "♮": { "codepoints": [9838], "characters": "\u266E" }, + "♮": { "codepoints": [9838], "characters": "\u266E" }, + "ℕ": { "codepoints": [8469], "characters": "\u2115" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, + "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, + "⩃": { "codepoints": [10819], "characters": "\u2A43" }, + "ň": { "codepoints": [328], "characters": "\u0148" }, + "ņ": { "codepoints": [326], "characters": "\u0146" }, + "≇": { "codepoints": [8775], "characters": "\u2247" }, + "⩭̸": { "codepoints": [10861, 824], "characters": "\u2A6D\u0338" }, + "⩂": { "codepoints": [10818], "characters": "\u2A42" }, + "н": { "codepoints": [1085], "characters": "\u043D" }, + "–": { "codepoints": [8211], "characters": "\u2013" }, + "≠": { "codepoints": [8800], "characters": "\u2260" }, + "⇗": { "codepoints": [8663], "characters": "\u21D7" }, + "⤤": { "codepoints": [10532], "characters": "\u2924" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "≐̸": { "codepoints": [8784, 824], "characters": "\u2250\u0338" }, + "≢": { "codepoints": [8802], "characters": "\u2262" }, + "⤨": { "codepoints": [10536], "characters": "\u2928" }, + "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "𝔫": { "codepoints": [120107], "characters": "\uD835\uDD2B" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "≵": { "codepoints": [8821], "characters": "\u2275" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "⇎": { "codepoints": [8654], "characters": "\u21CE" }, + "↮": { "codepoints": [8622], "characters": "\u21AE" }, + "⫲": { "codepoints": [10994], "characters": "\u2AF2" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "⋼": { "codepoints": [8956], "characters": "\u22FC" }, + "⋺": { "codepoints": [8954], "characters": "\u22FA" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "њ": { "codepoints": [1114], "characters": "\u045A" }, + "⇍": { "codepoints": [8653], "characters": "\u21CD" }, + "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, + "↚": { "codepoints": [8602], "characters": "\u219A" }, + "‥": { "codepoints": [8229], "characters": "\u2025" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "↚": { "codepoints": [8602], "characters": "\u219A" }, + "↮": { "codepoints": [8622], "characters": "\u21AE" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "≴": { "codepoints": [8820], "characters": "\u2274" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "𝕟": { "codepoints": [120159], "characters": "\uD835\uDD5F" }, + "¬": { "codepoints": [172], "characters": "\u00AC" }, + "¬": { "codepoints": [172], "characters": "\u00AC" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "⋹̸": { "codepoints": [8953, 824], "characters": "\u22F9\u0338" }, + "⋵̸": { "codepoints": [8949, 824], "characters": "\u22F5\u0338" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "⋷": { "codepoints": [8951], "characters": "\u22F7" }, + "⋶": { "codepoints": [8950], "characters": "\u22F6" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "⋾": { "codepoints": [8958], "characters": "\u22FE" }, + "⋽": { "codepoints": [8957], "characters": "\u22FD" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "⫽⃥": { "codepoints": [11005, 8421], "characters": "\u2AFD\u20E5" }, + "∂̸": { "codepoints": [8706, 824], "characters": "\u2202\u0338" }, + "⨔": { "codepoints": [10772], "characters": "\u2A14" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⋠": { "codepoints": [8928], "characters": "\u22E0" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⇏": { "codepoints": [8655], "characters": "\u21CF" }, + "↛": { "codepoints": [8603], "characters": "\u219B" }, + "⤳̸": { "codepoints": [10547, 824], "characters": "\u2933\u0338" }, + "↝̸": { "codepoints": [8605, 824], "characters": "\u219D\u0338" }, + "↛": { "codepoints": [8603], "characters": "\u219B" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⋡": { "codepoints": [8929], "characters": "\u22E1" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "𝓃": { "codepoints": [120003], "characters": "\uD835\uDCC3" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "≁": { "codepoints": [8769], "characters": "\u2241" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "⋢": { "codepoints": [8930], "characters": "\u22E2" }, + "⋣": { "codepoints": [8931], "characters": "\u22E3" }, + "⊄": { "codepoints": [8836], "characters": "\u2284" }, + "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "⊅": { "codepoints": [8837], "characters": "\u2285" }, + "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, + "≹": { "codepoints": [8825], "characters": "\u2279" }, + "ñ": { "codepoints": [241], "characters": "\u00F1" }, + "ñ": { "codepoints": [241], "characters": "\u00F1" }, + "≸": { "codepoints": [8824], "characters": "\u2278" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "ν": { "codepoints": [957], "characters": "\u03BD" }, + "#": { "codepoints": [35], "characters": "\u0023" }, + "№": { "codepoints": [8470], "characters": "\u2116" }, + " ": { "codepoints": [8199], "characters": "\u2007" }, + "⊭": { "codepoints": [8877], "characters": "\u22AD" }, + "⤄": { "codepoints": [10500], "characters": "\u2904" }, + "≍⃒": { "codepoints": [8781, 8402], "characters": "\u224D\u20D2" }, + "⊬": { "codepoints": [8876], "characters": "\u22AC" }, + "≥⃒": { "codepoints": [8805, 8402], "characters": "\u2265\u20D2" }, + ">⃒": { "codepoints": [62, 8402], "characters": "\u003E\u20D2" }, + "⧞": { "codepoints": [10718], "characters": "\u29DE" }, + "⤂": { "codepoints": [10498], "characters": "\u2902" }, + "≤⃒": { "codepoints": [8804, 8402], "characters": "\u2264\u20D2" }, + "<⃒": { "codepoints": [60, 8402], "characters": "\u003C\u20D2" }, + "⊴⃒": { "codepoints": [8884, 8402], "characters": "\u22B4\u20D2" }, + "⤃": { "codepoints": [10499], "characters": "\u2903" }, + "⊵⃒": { "codepoints": [8885, 8402], "characters": "\u22B5\u20D2" }, + "∼⃒": { "codepoints": [8764, 8402], "characters": "\u223C\u20D2" }, + "⇖": { "codepoints": [8662], "characters": "\u21D6" }, + "⤣": { "codepoints": [10531], "characters": "\u2923" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "⤧": { "codepoints": [10535], "characters": "\u2927" }, + "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, + "ó": { "codepoints": [243], "characters": "\u00F3" }, + "ó": { "codepoints": [243], "characters": "\u00F3" }, + "⊛": { "codepoints": [8859], "characters": "\u229B" }, + "⊚": { "codepoints": [8858], "characters": "\u229A" }, + "ô": { "codepoints": [244], "characters": "\u00F4" }, + "ô": { "codepoints": [244], "characters": "\u00F4" }, + "о": { "codepoints": [1086], "characters": "\u043E" }, + "⊝": { "codepoints": [8861], "characters": "\u229D" }, + "ő": { "codepoints": [337], "characters": "\u0151" }, + "⨸": { "codepoints": [10808], "characters": "\u2A38" }, + "⊙": { "codepoints": [8857], "characters": "\u2299" }, + "⦼": { "codepoints": [10684], "characters": "\u29BC" }, + "œ": { "codepoints": [339], "characters": "\u0153" }, + "⦿": { "codepoints": [10687], "characters": "\u29BF" }, + "𝔬": { "codepoints": [120108], "characters": "\uD835\uDD2C" }, + "˛": { "codepoints": [731], "characters": "\u02DB" }, + "ò": { "codepoints": [242], "characters": "\u00F2" }, + "ò": { "codepoints": [242], "characters": "\u00F2" }, + "⧁": { "codepoints": [10689], "characters": "\u29C1" }, + "⦵": { "codepoints": [10677], "characters": "\u29B5" }, + "Ω": { "codepoints": [937], "characters": "\u03A9" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "↺": { "codepoints": [8634], "characters": "\u21BA" }, + "⦾": { "codepoints": [10686], "characters": "\u29BE" }, + "⦻": { "codepoints": [10683], "characters": "\u29BB" }, + "‾": { "codepoints": [8254], "characters": "\u203E" }, + "⧀": { "codepoints": [10688], "characters": "\u29C0" }, + "ō": { "codepoints": [333], "characters": "\u014D" }, + "ω": { "codepoints": [969], "characters": "\u03C9" }, + "ο": { "codepoints": [959], "characters": "\u03BF" }, + "⦶": { "codepoints": [10678], "characters": "\u29B6" }, + "⊖": { "codepoints": [8854], "characters": "\u2296" }, + "𝕠": { "codepoints": [120160], "characters": "\uD835\uDD60" }, + "⦷": { "codepoints": [10679], "characters": "\u29B7" }, + "⦹": { "codepoints": [10681], "characters": "\u29B9" }, + "⊕": { "codepoints": [8853], "characters": "\u2295" }, + "∨": { "codepoints": [8744], "characters": "\u2228" }, + "↻": { "codepoints": [8635], "characters": "\u21BB" }, + "⩝": { "codepoints": [10845], "characters": "\u2A5D" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ª": { "codepoints": [170], "characters": "\u00AA" }, + "ª": { "codepoints": [170], "characters": "\u00AA" }, + "º": { "codepoints": [186], "characters": "\u00BA" }, + "º": { "codepoints": [186], "characters": "\u00BA" }, + "⊶": { "codepoints": [8886], "characters": "\u22B6" }, + "⩖": { "codepoints": [10838], "characters": "\u2A56" }, + "⩗": { "codepoints": [10839], "characters": "\u2A57" }, + "⩛": { "codepoints": [10843], "characters": "\u2A5B" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ø": { "codepoints": [248], "characters": "\u00F8" }, + "ø": { "codepoints": [248], "characters": "\u00F8" }, + "⊘": { "codepoints": [8856], "characters": "\u2298" }, + "õ": { "codepoints": [245], "characters": "\u00F5" }, + "õ": { "codepoints": [245], "characters": "\u00F5" }, + "⊗": { "codepoints": [8855], "characters": "\u2297" }, + "⨶": { "codepoints": [10806], "characters": "\u2A36" }, + "ö": { "codepoints": [246], "characters": "\u00F6" }, + "ö": { "codepoints": [246], "characters": "\u00F6" }, + "⌽": { "codepoints": [9021], "characters": "\u233D" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "¶": { "codepoints": [182], "characters": "\u00B6" }, + "¶": { "codepoints": [182], "characters": "\u00B6" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "⫳": { "codepoints": [10995], "characters": "\u2AF3" }, + "⫽": { "codepoints": [11005], "characters": "\u2AFD" }, + "∂": { "codepoints": [8706], "characters": "\u2202" }, + "п": { "codepoints": [1087], "characters": "\u043F" }, + "%": { "codepoints": [37], "characters": "\u0025" }, + ".": { "codepoints": [46], "characters": "\u002E" }, + "‰": { "codepoints": [8240], "characters": "\u2030" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "‱": { "codepoints": [8241], "characters": "\u2031" }, + "𝔭": { "codepoints": [120109], "characters": "\uD835\uDD2D" }, + "φ": { "codepoints": [966], "characters": "\u03C6" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "☎": { "codepoints": [9742], "characters": "\u260E" }, + "π": { "codepoints": [960], "characters": "\u03C0" }, + "⋔": { "codepoints": [8916], "characters": "\u22D4" }, + "ϖ": { "codepoints": [982], "characters": "\u03D6" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ℎ": { "codepoints": [8462], "characters": "\u210E" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "+": { "codepoints": [43], "characters": "\u002B" }, + "⨣": { "codepoints": [10787], "characters": "\u2A23" }, + "⊞": { "codepoints": [8862], "characters": "\u229E" }, + "⨢": { "codepoints": [10786], "characters": "\u2A22" }, + "∔": { "codepoints": [8724], "characters": "\u2214" }, + "⨥": { "codepoints": [10789], "characters": "\u2A25" }, + "⩲": { "codepoints": [10866], "characters": "\u2A72" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "⨦": { "codepoints": [10790], "characters": "\u2A26" }, + "⨧": { "codepoints": [10791], "characters": "\u2A27" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "⨕": { "codepoints": [10773], "characters": "\u2A15" }, + "𝕡": { "codepoints": [120161], "characters": "\uD835\uDD61" }, + "£": { "codepoints": [163], "characters": "\u00A3" }, + "£": { "codepoints": [163], "characters": "\u00A3" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪳": { "codepoints": [10931], "characters": "\u2AB3" }, + "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, + "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, + "⋨": { "codepoints": [8936], "characters": "\u22E8" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "′": { "codepoints": [8242], "characters": "\u2032" }, + "ℙ": { "codepoints": [8473], "characters": "\u2119" }, + "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, + "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, + "⋨": { "codepoints": [8936], "characters": "\u22E8" }, + "∏": { "codepoints": [8719], "characters": "\u220F" }, + "⌮": { "codepoints": [9006], "characters": "\u232E" }, + "⌒": { "codepoints": [8978], "characters": "\u2312" }, + "⌓": { "codepoints": [8979], "characters": "\u2313" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "⊰": { "codepoints": [8880], "characters": "\u22B0" }, + "𝓅": { "codepoints": [120005], "characters": "\uD835\uDCC5" }, + "ψ": { "codepoints": [968], "characters": "\u03C8" }, + " ": { "codepoints": [8200], "characters": "\u2008" }, + "𝔮": { "codepoints": [120110], "characters": "\uD835\uDD2E" }, + "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, + "𝕢": { "codepoints": [120162], "characters": "\uD835\uDD62" }, + "⁗": { "codepoints": [8279], "characters": "\u2057" }, + "𝓆": { "codepoints": [120006], "characters": "\uD835\uDCC6" }, + "ℍ": { "codepoints": [8461], "characters": "\u210D" }, + "⨖": { "codepoints": [10774], "characters": "\u2A16" }, + "?": { "codepoints": [63], "characters": "\u003F" }, + "≟": { "codepoints": [8799], "characters": "\u225F" }, + """: { "codepoints": [34], "characters": "\u0022" }, + """: { "codepoints": [34], "characters": "\u0022" }, + "⇛": { "codepoints": [8667], "characters": "\u21DB" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "⤜": { "codepoints": [10524], "characters": "\u291C" }, + "⤏": { "codepoints": [10511], "characters": "\u290F" }, + "⥤": { "codepoints": [10596], "characters": "\u2964" }, + "∽̱": { "codepoints": [8765, 817], "characters": "\u223D\u0331" }, + "ŕ": { "codepoints": [341], "characters": "\u0155" }, + "√": { "codepoints": [8730], "characters": "\u221A" }, + "⦳": { "codepoints": [10675], "characters": "\u29B3" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "⦒": { "codepoints": [10642], "characters": "\u2992" }, + "⦥": { "codepoints": [10661], "characters": "\u29A5" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "»": { "codepoints": [187], "characters": "\u00BB" }, + "»": { "codepoints": [187], "characters": "\u00BB" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "⥵": { "codepoints": [10613], "characters": "\u2975" }, + "⇥": { "codepoints": [8677], "characters": "\u21E5" }, + "⤠": { "codepoints": [10528], "characters": "\u2920" }, + "⤳": { "codepoints": [10547], "characters": "\u2933" }, + "⤞": { "codepoints": [10526], "characters": "\u291E" }, + "↪": { "codepoints": [8618], "characters": "\u21AA" }, + "↬": { "codepoints": [8620], "characters": "\u21AC" }, + "⥅": { "codepoints": [10565], "characters": "\u2945" }, + "⥴": { "codepoints": [10612], "characters": "\u2974" }, + "↣": { "codepoints": [8611], "characters": "\u21A3" }, + "↝": { "codepoints": [8605], "characters": "\u219D" }, + "⤚": { "codepoints": [10522], "characters": "\u291A" }, + "∶": { "codepoints": [8758], "characters": "\u2236" }, + "ℚ": { "codepoints": [8474], "characters": "\u211A" }, + "⤍": { "codepoints": [10509], "characters": "\u290D" }, + "❳": { "codepoints": [10099], "characters": "\u2773" }, + "}": { "codepoints": [125], "characters": "\u007D" }, + "]": { "codepoints": [93], "characters": "\u005D" }, + "⦌": { "codepoints": [10636], "characters": "\u298C" }, + "⦎": { "codepoints": [10638], "characters": "\u298E" }, + "⦐": { "codepoints": [10640], "characters": "\u2990" }, + "ř": { "codepoints": [345], "characters": "\u0159" }, + "ŗ": { "codepoints": [343], "characters": "\u0157" }, + "⌉": { "codepoints": [8969], "characters": "\u2309" }, + "}": { "codepoints": [125], "characters": "\u007D" }, + "р": { "codepoints": [1088], "characters": "\u0440" }, + "⤷": { "codepoints": [10551], "characters": "\u2937" }, + "⥩": { "codepoints": [10601], "characters": "\u2969" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "↳": { "codepoints": [8627], "characters": "\u21B3" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "ℛ": { "codepoints": [8475], "characters": "\u211B" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "ℝ": { "codepoints": [8477], "characters": "\u211D" }, + "▭": { "codepoints": [9645], "characters": "\u25AD" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "⥽": { "codepoints": [10621], "characters": "\u297D" }, + "⌋": { "codepoints": [8971], "characters": "\u230B" }, + "𝔯": { "codepoints": [120111], "characters": "\uD835\uDD2F" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⥬": { "codepoints": [10604], "characters": "\u296C" }, + "ρ": { "codepoints": [961], "characters": "\u03C1" }, + "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "↣": { "codepoints": [8611], "characters": "\u21A3" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "⇉": { "codepoints": [8649], "characters": "\u21C9" }, + "↝": { "codepoints": [8605], "characters": "\u219D" }, + "⋌": { "codepoints": [8908], "characters": "\u22CC" }, + "˚": { "codepoints": [730], "characters": "\u02DA" }, + "≓": { "codepoints": [8787], "characters": "\u2253" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "‏": { "codepoints": [8207], "characters": "\u200F" }, + "⎱": { "codepoints": [9137], "characters": "\u23B1" }, + "⎱": { "codepoints": [9137], "characters": "\u23B1" }, + "⫮": { "codepoints": [10990], "characters": "\u2AEE" }, + "⟭": { "codepoints": [10221], "characters": "\u27ED" }, + "⇾": { "codepoints": [8702], "characters": "\u21FE" }, + "⟧": { "codepoints": [10215], "characters": "\u27E7" }, + "⦆": { "codepoints": [10630], "characters": "\u2986" }, + "𝕣": { "codepoints": [120163], "characters": "\uD835\uDD63" }, + "⨮": { "codepoints": [10798], "characters": "\u2A2E" }, + "⨵": { "codepoints": [10805], "characters": "\u2A35" }, + ")": { "codepoints": [41], "characters": "\u0029" }, + "⦔": { "codepoints": [10644], "characters": "\u2994" }, + "⨒": { "codepoints": [10770], "characters": "\u2A12" }, + "⇉": { "codepoints": [8649], "characters": "\u21C9" }, + "›": { "codepoints": [8250], "characters": "\u203A" }, + "𝓇": { "codepoints": [120007], "characters": "\uD835\uDCC7" }, + "↱": { "codepoints": [8625], "characters": "\u21B1" }, + "]": { "codepoints": [93], "characters": "\u005D" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "⋌": { "codepoints": [8908], "characters": "\u22CC" }, + "⋊": { "codepoints": [8906], "characters": "\u22CA" }, + "▹": { "codepoints": [9657], "characters": "\u25B9" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "▸": { "codepoints": [9656], "characters": "\u25B8" }, + "⧎": { "codepoints": [10702], "characters": "\u29CE" }, + "⥨": { "codepoints": [10600], "characters": "\u2968" }, + "℞": { "codepoints": [8478], "characters": "\u211E" }, + "ś": { "codepoints": [347], "characters": "\u015B" }, + "‚": { "codepoints": [8218], "characters": "\u201A" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪴": { "codepoints": [10932], "characters": "\u2AB4" }, + "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, + "š": { "codepoints": [353], "characters": "\u0161" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "ş": { "codepoints": [351], "characters": "\u015F" }, + "ŝ": { "codepoints": [349], "characters": "\u015D" }, + "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, + "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, + "⋩": { "codepoints": [8937], "characters": "\u22E9" }, + "⨓": { "codepoints": [10771], "characters": "\u2A13" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "с": { "codepoints": [1089], "characters": "\u0441" }, + "⋅": { "codepoints": [8901], "characters": "\u22C5" }, + "⊡": { "codepoints": [8865], "characters": "\u22A1" }, + "⩦": { "codepoints": [10854], "characters": "\u2A66" }, + "⇘": { "codepoints": [8664], "characters": "\u21D8" }, + "⤥": { "codepoints": [10533], "characters": "\u2925" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "§": { "codepoints": [167], "characters": "\u00A7" }, + "§": { "codepoints": [167], "characters": "\u00A7" }, + ";": { "codepoints": [59], "characters": "\u003B" }, + "⤩": { "codepoints": [10537], "characters": "\u2929" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "✶": { "codepoints": [10038], "characters": "\u2736" }, + "𝔰": { "codepoints": [120112], "characters": "\uD835\uDD30" }, + "⌢": { "codepoints": [8994], "characters": "\u2322" }, + "♯": { "codepoints": [9839], "characters": "\u266F" }, + "щ": { "codepoints": [1097], "characters": "\u0449" }, + "ш": { "codepoints": [1096], "characters": "\u0448" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "­": { "codepoints": [173], "characters": "\u00AD" }, + "­": { "codepoints": [173], "characters": "\u00AD" }, + "σ": { "codepoints": [963], "characters": "\u03C3" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "⩪": { "codepoints": [10858], "characters": "\u2A6A" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "⪞": { "codepoints": [10910], "characters": "\u2A9E" }, + "⪠": { "codepoints": [10912], "characters": "\u2AA0" }, + "⪝": { "codepoints": [10909], "characters": "\u2A9D" }, + "⪟": { "codepoints": [10911], "characters": "\u2A9F" }, + "≆": { "codepoints": [8774], "characters": "\u2246" }, + "⨤": { "codepoints": [10788], "characters": "\u2A24" }, + "⥲": { "codepoints": [10610], "characters": "\u2972" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⨳": { "codepoints": [10803], "characters": "\u2A33" }, + "⧤": { "codepoints": [10724], "characters": "\u29E4" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "⌣": { "codepoints": [8995], "characters": "\u2323" }, + "⪪": { "codepoints": [10922], "characters": "\u2AAA" }, + "⪬": { "codepoints": [10924], "characters": "\u2AAC" }, + "⪬︀": { "codepoints": [10924, 65024], "characters": "\u2AAC\uFE00" }, + "ь": { "codepoints": [1100], "characters": "\u044C" }, + "/": { "codepoints": [47], "characters": "\u002F" }, + "⧄": { "codepoints": [10692], "characters": "\u29C4" }, + "⌿": { "codepoints": [9023], "characters": "\u233F" }, + "𝕤": { "codepoints": [120164], "characters": "\uD835\uDD64" }, + "♠": { "codepoints": [9824], "characters": "\u2660" }, + "♠": { "codepoints": [9824], "characters": "\u2660" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "⊓": { "codepoints": [8851], "characters": "\u2293" }, + "⊓︀": { "codepoints": [8851, 65024], "characters": "\u2293\uFE00" }, + "⊔": { "codepoints": [8852], "characters": "\u2294" }, + "⊔︀": { "codepoints": [8852, 65024], "characters": "\u2294\uFE00" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "𝓈": { "codepoints": [120008], "characters": "\uD835\uDCC8" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⌣": { "codepoints": [8995], "characters": "\u2323" }, + "⋆": { "codepoints": [8902], "characters": "\u22C6" }, + "☆": { "codepoints": [9734], "characters": "\u2606" }, + "★": { "codepoints": [9733], "characters": "\u2605" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "⊂": { "codepoints": [8834], "characters": "\u2282" }, + "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, + "⪽": { "codepoints": [10941], "characters": "\u2ABD" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "⫃": { "codepoints": [10947], "characters": "\u2AC3" }, + "⫁": { "codepoints": [10945], "characters": "\u2AC1" }, + "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, + "⊊": { "codepoints": [8842], "characters": "\u228A" }, + "⪿": { "codepoints": [10943], "characters": "\u2ABF" }, + "⥹": { "codepoints": [10617], "characters": "\u2979" }, + "⊂": { "codepoints": [8834], "characters": "\u2282" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, + "⊊": { "codepoints": [8842], "characters": "\u228A" }, + "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, + "⫇": { "codepoints": [10951], "characters": "\u2AC7" }, + "⫕": { "codepoints": [10965], "characters": "\u2AD5" }, + "⫓": { "codepoints": [10963], "characters": "\u2AD3" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, + "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, + "⋩": { "codepoints": [8937], "characters": "\u22E9" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "∑": { "codepoints": [8721], "characters": "\u2211" }, + "♪": { "codepoints": [9834], "characters": "\u266A" }, + "¹": { "codepoints": [185], "characters": "\u00B9" }, + "¹": { "codepoints": [185], "characters": "\u00B9" }, + "²": { "codepoints": [178], "characters": "\u00B2" }, + "²": { "codepoints": [178], "characters": "\u00B2" }, + "³": { "codepoints": [179], "characters": "\u00B3" }, + "³": { "codepoints": [179], "characters": "\u00B3" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, + "⪾": { "codepoints": [10942], "characters": "\u2ABE" }, + "⫘": { "codepoints": [10968], "characters": "\u2AD8" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⫄": { "codepoints": [10948], "characters": "\u2AC4" }, + "⟉": { "codepoints": [10185], "characters": "\u27C9" }, + "⫗": { "codepoints": [10967], "characters": "\u2AD7" }, + "⥻": { "codepoints": [10619], "characters": "\u297B" }, + "⫂": { "codepoints": [10946], "characters": "\u2AC2" }, + "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, + "⊋": { "codepoints": [8843], "characters": "\u228B" }, + "⫀": { "codepoints": [10944], "characters": "\u2AC0" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, + "⊋": { "codepoints": [8843], "characters": "\u228B" }, + "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, + "⫈": { "codepoints": [10952], "characters": "\u2AC8" }, + "⫔": { "codepoints": [10964], "characters": "\u2AD4" }, + "⫖": { "codepoints": [10966], "characters": "\u2AD6" }, + "⇙": { "codepoints": [8665], "characters": "\u21D9" }, + "⤦": { "codepoints": [10534], "characters": "\u2926" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "⤪": { "codepoints": [10538], "characters": "\u292A" }, + "ß": { "codepoints": [223], "characters": "\u00DF" }, + "ß": { "codepoints": [223], "characters": "\u00DF" }, + "⌖": { "codepoints": [8982], "characters": "\u2316" }, + "τ": { "codepoints": [964], "characters": "\u03C4" }, + "⎴": { "codepoints": [9140], "characters": "\u23B4" }, + "ť": { "codepoints": [357], "characters": "\u0165" }, + "ţ": { "codepoints": [355], "characters": "\u0163" }, + "т": { "codepoints": [1090], "characters": "\u0442" }, + "⃛": { "codepoints": [8411], "characters": "\u20DB" }, + "⌕": { "codepoints": [8981], "characters": "\u2315" }, + "𝔱": { "codepoints": [120113], "characters": "\uD835\uDD31" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "θ": { "codepoints": [952], "characters": "\u03B8" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + " ": { "codepoints": [8201], "characters": "\u2009" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "þ": { "codepoints": [254], "characters": "\u00FE" }, + "þ": { "codepoints": [254], "characters": "\u00FE" }, + "˜": { "codepoints": [732], "characters": "\u02DC" }, + "×": { "codepoints": [215], "characters": "\u00D7" }, + "×": { "codepoints": [215], "characters": "\u00D7" }, + "⊠": { "codepoints": [8864], "characters": "\u22A0" }, + "⨱": { "codepoints": [10801], "characters": "\u2A31" }, + "⨰": { "codepoints": [10800], "characters": "\u2A30" }, + "∭": { "codepoints": [8749], "characters": "\u222D" }, + "⤨": { "codepoints": [10536], "characters": "\u2928" }, + "⊤": { "codepoints": [8868], "characters": "\u22A4" }, + "⌶": { "codepoints": [9014], "characters": "\u2336" }, + "⫱": { "codepoints": [10993], "characters": "\u2AF1" }, + "𝕥": { "codepoints": [120165], "characters": "\uD835\uDD65" }, + "⫚": { "codepoints": [10970], "characters": "\u2ADA" }, + "⤩": { "codepoints": [10537], "characters": "\u2929" }, + "‴": { "codepoints": [8244], "characters": "\u2034" }, + "™": { "codepoints": [8482], "characters": "\u2122" }, + "▵": { "codepoints": [9653], "characters": "\u25B5" }, + "▿": { "codepoints": [9663], "characters": "\u25BF" }, + "◃": { "codepoints": [9667], "characters": "\u25C3" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "≜": { "codepoints": [8796], "characters": "\u225C" }, + "▹": { "codepoints": [9657], "characters": "\u25B9" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "◬": { "codepoints": [9708], "characters": "\u25EC" }, + "≜": { "codepoints": [8796], "characters": "\u225C" }, + "⨺": { "codepoints": [10810], "characters": "\u2A3A" }, + "⨹": { "codepoints": [10809], "characters": "\u2A39" }, + "⧍": { "codepoints": [10701], "characters": "\u29CD" }, + "⨻": { "codepoints": [10811], "characters": "\u2A3B" }, + "⏢": { "codepoints": [9186], "characters": "\u23E2" }, + "𝓉": { "codepoints": [120009], "characters": "\uD835\uDCC9" }, + "ц": { "codepoints": [1094], "characters": "\u0446" }, + "ћ": { "codepoints": [1115], "characters": "\u045B" }, + "ŧ": { "codepoints": [359], "characters": "\u0167" }, + "≬": { "codepoints": [8812], "characters": "\u226C" }, + "↞": { "codepoints": [8606], "characters": "\u219E" }, + "↠": { "codepoints": [8608], "characters": "\u21A0" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⥣": { "codepoints": [10595], "characters": "\u2963" }, + "ú": { "codepoints": [250], "characters": "\u00FA" }, + "ú": { "codepoints": [250], "characters": "\u00FA" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "ў": { "codepoints": [1118], "characters": "\u045E" }, + "ŭ": { "codepoints": [365], "characters": "\u016D" }, + "û": { "codepoints": [251], "characters": "\u00FB" }, + "û": { "codepoints": [251], "characters": "\u00FB" }, + "у": { "codepoints": [1091], "characters": "\u0443" }, + "⇅": { "codepoints": [8645], "characters": "\u21C5" }, + "ű": { "codepoints": [369], "characters": "\u0171" }, + "⥮": { "codepoints": [10606], "characters": "\u296E" }, + "⥾": { "codepoints": [10622], "characters": "\u297E" }, + "𝔲": { "codepoints": [120114], "characters": "\uD835\uDD32" }, + "ù": { "codepoints": [249], "characters": "\u00F9" }, + "ù": { "codepoints": [249], "characters": "\u00F9" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "▀": { "codepoints": [9600], "characters": "\u2580" }, + "⌜": { "codepoints": [8988], "characters": "\u231C" }, + "⌜": { "codepoints": [8988], "characters": "\u231C" }, + "⌏": { "codepoints": [8975], "characters": "\u230F" }, + "◸": { "codepoints": [9720], "characters": "\u25F8" }, + "ū": { "codepoints": [363], "characters": "\u016B" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "ų": { "codepoints": [371], "characters": "\u0173" }, + "𝕦": { "codepoints": [120166], "characters": "\uD835\uDD66" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "⊎": { "codepoints": [8846], "characters": "\u228E" }, + "υ": { "codepoints": [965], "characters": "\u03C5" }, + "ϒ": { "codepoints": [978], "characters": "\u03D2" }, + "υ": { "codepoints": [965], "characters": "\u03C5" }, + "⇈": { "codepoints": [8648], "characters": "\u21C8" }, + "⌝": { "codepoints": [8989], "characters": "\u231D" }, + "⌝": { "codepoints": [8989], "characters": "\u231D" }, + "⌎": { "codepoints": [8974], "characters": "\u230E" }, + "ů": { "codepoints": [367], "characters": "\u016F" }, + "◹": { "codepoints": [9721], "characters": "\u25F9" }, + "𝓊": { "codepoints": [120010], "characters": "\uD835\uDCCA" }, + "⋰": { "codepoints": [8944], "characters": "\u22F0" }, + "ũ": { "codepoints": [361], "characters": "\u0169" }, + "▵": { "codepoints": [9653], "characters": "\u25B5" }, + "▴": { "codepoints": [9652], "characters": "\u25B4" }, + "⇈": { "codepoints": [8648], "characters": "\u21C8" }, + "ü": { "codepoints": [252], "characters": "\u00FC" }, + "ü": { "codepoints": [252], "characters": "\u00FC" }, + "⦧": { "codepoints": [10663], "characters": "\u29A7" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "⫨": { "codepoints": [10984], "characters": "\u2AE8" }, + "⫩": { "codepoints": [10985], "characters": "\u2AE9" }, + "⊨": { "codepoints": [8872], "characters": "\u22A8" }, + "⦜": { "codepoints": [10652], "characters": "\u299C" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "ϖ": { "codepoints": [982], "characters": "\u03D6" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, + "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, + "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, + "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "в": { "codepoints": [1074], "characters": "\u0432" }, + "⊢": { "codepoints": [8866], "characters": "\u22A2" }, + "∨": { "codepoints": [8744], "characters": "\u2228" }, + "⊻": { "codepoints": [8891], "characters": "\u22BB" }, + "≚": { "codepoints": [8794], "characters": "\u225A" }, + "⋮": { "codepoints": [8942], "characters": "\u22EE" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "𝔳": { "codepoints": [120115], "characters": "\uD835\uDD33" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "𝕧": { "codepoints": [120167], "characters": "\uD835\uDD67" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "𝓋": { "codepoints": [120011], "characters": "\uD835\uDCCB" }, + "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, + "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, + "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, + "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, + "⦚": { "codepoints": [10650], "characters": "\u299A" }, + "ŵ": { "codepoints": [373], "characters": "\u0175" }, + "⩟": { "codepoints": [10847], "characters": "\u2A5F" }, + "∧": { "codepoints": [8743], "characters": "\u2227" }, + "≙": { "codepoints": [8793], "characters": "\u2259" }, + "℘": { "codepoints": [8472], "characters": "\u2118" }, + "𝔴": { "codepoints": [120116], "characters": "\uD835\uDD34" }, + "𝕨": { "codepoints": [120168], "characters": "\uD835\uDD68" }, + "℘": { "codepoints": [8472], "characters": "\u2118" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + "𝓌": { "codepoints": [120012], "characters": "\uD835\uDCCC" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "◯": { "codepoints": [9711], "characters": "\u25EF" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "▽": { "codepoints": [9661], "characters": "\u25BD" }, + "𝔵": { "codepoints": [120117], "characters": "\uD835\uDD35" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "ξ": { "codepoints": [958], "characters": "\u03BE" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟼": { "codepoints": [10236], "characters": "\u27FC" }, + "⋻": { "codepoints": [8955], "characters": "\u22FB" }, + "⨀": { "codepoints": [10752], "characters": "\u2A00" }, + "𝕩": { "codepoints": [120169], "characters": "\uD835\uDD69" }, + "⨁": { "codepoints": [10753], "characters": "\u2A01" }, + "⨂": { "codepoints": [10754], "characters": "\u2A02" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "𝓍": { "codepoints": [120013], "characters": "\uD835\uDCCD" }, + "⨆": { "codepoints": [10758], "characters": "\u2A06" }, + "⨄": { "codepoints": [10756], "characters": "\u2A04" }, + "△": { "codepoints": [9651], "characters": "\u25B3" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "ý": { "codepoints": [253], "characters": "\u00FD" }, + "ý": { "codepoints": [253], "characters": "\u00FD" }, + "я": { "codepoints": [1103], "characters": "\u044F" }, + "ŷ": { "codepoints": [375], "characters": "\u0177" }, + "ы": { "codepoints": [1099], "characters": "\u044B" }, + "¥": { "codepoints": [165], "characters": "\u00A5" }, + "¥": { "codepoints": [165], "characters": "\u00A5" }, + "𝔶": { "codepoints": [120118], "characters": "\uD835\uDD36" }, + "ї": { "codepoints": [1111], "characters": "\u0457" }, + "𝕪": { "codepoints": [120170], "characters": "\uD835\uDD6A" }, + "𝓎": { "codepoints": [120014], "characters": "\uD835\uDCCE" }, + "ю": { "codepoints": [1102], "characters": "\u044E" }, + "ÿ": { "codepoints": [255], "characters": "\u00FF" }, + "ÿ": { "codepoints": [255], "characters": "\u00FF" }, + "ź": { "codepoints": [378], "characters": "\u017A" }, + "ž": { "codepoints": [382], "characters": "\u017E" }, + "з": { "codepoints": [1079], "characters": "\u0437" }, + "ż": { "codepoints": [380], "characters": "\u017C" }, + "ℨ": { "codepoints": [8488], "characters": "\u2128" }, + "ζ": { "codepoints": [950], "characters": "\u03B6" }, + "𝔷": { "codepoints": [120119], "characters": "\uD835\uDD37" }, + "ж": { "codepoints": [1078], "characters": "\u0436" }, + "⇝": { "codepoints": [8669], "characters": "\u21DD" }, + "𝕫": { "codepoints": [120171], "characters": "\uD835\uDD6B" }, + "𝓏": { "codepoints": [120015], "characters": "\uD835\uDCCF" }, + "‍": { "codepoints": [8205], "characters": "\u200D" }, + "‌": { "codepoints": [8204], "characters": "\u200C" } +} diff --git a/src/entity.nim b/src/entity.nim new file mode 100644 index 00000000..3ebe9df0 --- /dev/null +++ b/src/entity.nim @@ -0,0 +1,18 @@ +import radixtree +import json +import tables +import strutils +import unicode +import twtstr + +proc genEntityMap(): RadixTree[string] = + let entity = staticRead"entity.json" + let entityJson = parseJson(entity) + var entityMap = newRadixTree[string]() + + for k, v in entityJson: + entityMap[k.substr(1)] = v{"characters"}.getStr() + + return entityMap + +const entityMap* = genEntityMap() diff --git a/src/enums.nim b/src/enums.nim new file mode 100644 index 00000000..a0606332 --- /dev/null +++ b/src/enums.nim @@ -0,0 +1,103 @@ +type + NodeType* = + enum + UNKNOWN_NODE = 0, + ELEMENT_NODE = 1, + ATTRIBUTE_NODE = 2, + TEXT_NODE = 3, + CDATA_SECTION_NODE = 4, + ENTITY_REFERENCE_NODE = 5, + ENTITY_NODE = 6 + PROCESSING_INSTRUCTION_NODE = 7, + COMMENT_NODE = 8, + DOCUMENT_NODE = 9, + DOCUMENT_TYPE_NODE = 10, + DOCUMENT_FRAGMENT_NODE = 11, + NOTATION_NODE = 12 + + DisplayType* = + enum + DISPLAY_INLINE, DISPLAY_BLOCK, DISPLAY_LIST_ITEM, DISPLAY_TABLE_COLUMN, + DISPLAY_INLINE_BLOCK, DISPLAY_NONE + + InputType* = + enum + INPUT_UNKNOWN, INPUT_BUTTON, INPUT_CHECKBOX, INPUT_COLOR, INPUT_DATE, + INPUT_DATETIME_LOCAL, INPUT_EMAIL, INPUT_FILE, INPUT_HIDDEN, INPUT_IMAGE, + INPUT_MONTH, INPUT_NUMBER, INPUT_PASSWORD, INPUT_RADIO, INPUT_RANGE, + INPUT_RESET, INPUT_SEARCH, INPUT_SUBMIT, INPUT_TEL, INPUT_TEXT, INPUT_TIME, + INPUT_URL, INPUT_WEEK + + WhitespaceType* = + enum + WHITESPACE_UNKNOWN, WHITESPACE_NORMAL, WHITESPACE_NOWRAP, WHITESPACE_PRE, + WHITESPACE_PRE_LINE, WHITESPACE_PRE_WRAP, WHITESPACE_INITIAL, + WHITESPACE_INHERIT + + TagType* = + enum + TAG_UNKNOWN, TAG_HTML, TAG_BASE, TAG_HEAD, TAG_LINK, TAG_META, TAG_STYLE, + TAG_TITLE, TAG_BODY, TAG_ADDRESS, TAG_ARTICLE, TAG_ASIDE, TAG_FOOTER, + TAG_HEADER, TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6, TAG_HGROUP, + TAG_MAIN, TAG_NAV, TAG_SECTION, TAG_BLOCKQUOTE, TAG_DD, TAG_DIV, TAG_DL, + TAG_DT, TAG_FIGCAPTION, TAG_FIGURE, TAG_HR, TAG_LI, TAG_OL, TAG_P, TAG_PRE, + TAG_UL, TAG_A, TAG_ABBR, TAG_B, TAG_BDI, TAG_BDO, TAG_BR, TAG_CITE, + TAG_CODE, TAG_DATA, TAG_DFN, TAG_EM, TAG_I, TAG_KBD, TAG_MARK, TAG_Q, + TAG_RB, TAG_RP, TAG_RT, TAG_RTC, TAG_RUBY, TAG_S, TAG_SAMP, TAG_SMALL, + TAG_SPAN, TAG_STRONG, TAG_SUB, TAG_SUP, TAG_TIME, TAG_U, TAG_VAR, TAG_WBR, + TAG_AREA, TAG_AUDIO, TAG_IMG, TAG_MAP, TAG_TRACK, TAG_VIDEO, + TAG_IFRAME, TAG_OBJECT, TAG_PARAM, TAG_PICTURE, TAG_PORTAL, TAG_SOURCE, + TAG_CANVAS, TAG_NOSCRIPT, TAG_SCRIPT, TAG_DEL, TAG_INS, TAG_CAPTION, + TAG_COL, TAG_COLGROUP, TAG_TABLE, TAG_TBODY, TAG_TD, TAG_TFOOT, TAG_TH, + TAG_THEAD, TAG_TR, TAG_BUTTON, TAG_DATALIST, TAG_FIELDSET, TAG_FORM, + TAG_INPUT, TAG_LABEL, TAG_LEGEND, TAG_METER, TAG_OPTGROUP, TAG_OPTION, + TAG_OUTPUT, TAG_PROGRESS, TAG_SELECT, TAG_TEXTAREA, TAG_DETAILS, + TAG_DIALOG, TAG_MENU, TAG_SUMMARY, TAG_BLINK, TAG_CENTER, TAG_CONTENT, + TAG_DIR, TAG_FONT, TAG_FRAME, TAG_NOFRAMES, TAG_FRAMESET, TAG_STRIKE, TAG_TT + + CSSTokenType* = + enum + CSS_NO_TOKEN, CSS_IDENT_TOKEN, CSS_FUNCTION_TOKEN, CSS_AT_KEYWORD_TOKEN, + CSS_HASH_TOKEN, CSS_STRING_TOKEN, CSS_BAD_STRING_TOKEN, CSS_URL_TOKEN, + CSS_BAD_URL_TOKEN, CSS_DELIM_TOKEN, CSS_NUMBER_TOKEN, CSS_PERCENTAGE_TOKEN, + CSS_DIMENSION_TOKEN, CSS_WHITESPACE_TOKEN, CSS_CDO_TOKEN, CSS_CDC_TOKEN, + CSS_COLON_TOKEN, CSS_SEMICOLON_TOKEN, CSS_COMMA_TOKEN, CSS_OBRACKET_TOKEN, + CSS_CBRACKET_TOKEN, CSS_OPAREN_TOKEN, CSS_CPAREN_TOKEN, CSS_OBRACE_TOKEN, + CSS_CBRACE_TOKEN + +const DisplayInlineTags* = { + TAG_A, TAG_ABBR, TAG_B, TAG_BDO, TAG_BR, TAG_BUTTON, TAG_CITE, TAG_CODE, + TAG_DEL, TAG_DFN, TAG_EM, TAG_FONT, TAG_I, TAG_IMG, TAG_INS, TAG_INPUT, + TAG_IFRAME, TAG_KBD, TAG_LABEL, TAG_MAP, TAG_OBJECT, TAG_Q, TAG_SAMP, + TAG_SCRIPT, TAG_SELECT, TAG_SMALL, TAG_SPAN, TAG_STRONG, TAG_SUB, TAG_SUP, + TAG_TEXTAREA, TAG_TT, TAG_VAR, TAG_FONT, TAG_IFRAME, TAG_U, TAG_S, TAG_STRIKE, + TAG_FRAME, TAG_IMG, TAG_INPUT +} + +const DisplayNoneTags* = { + TAG_AREA, TAG_BASE, TAG_SOURCE, TAG_TRACK, TAG_LINK, TAG_META, TAG_PARAM, TAG_WBR +} + +const DisplayInlineBlockTags* = { + TAG_IMG +} + +const DisplayTableColumnTags* = { + TAG_COL +} + +const DisplayBlockTags* = { + TAG_ADDRESS, TAG_BLOCKQUOTE, TAG_CENTER, TAG_DEL, TAG_DIR, TAG_DIV, TAG_DL, + TAG_FIELDSET, TAG_FORM, TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6, + TAG_HR, TAG_INS, TAG_MENU, TAG_NOFRAMES, TAG_NOSCRIPT, TAG_OL, TAG_P, TAG_PRE, + TAG_TABLE, TAG_UL, TAG_CENTER, TAG_DIR, TAG_MENU, TAG_NOFRAMES, TAG_BODY, +} + +const SelfClosingTagTypes* = { + TAG_LI, TAG_P +} + +const VoidTagTypes* = { + TAG_AREA, TAG_BASE, TAG_BR, TAG_COL, TAG_FRAME, TAG_HR, TAG_IMG, TAG_INPUT, + TAG_SOURCE, TAG_TRACK, TAG_LINK, TAG_META, TAG_PARAM, TAG_WBR, TAG_HR +} diff --git a/src/main.nim b/src/main.nim new file mode 100644 index 00000000..bc212ef0 --- /dev/null +++ b/src/main.nim @@ -0,0 +1,65 @@ +import httpClient +import uri +import os +import streams + +import display +import termattrs +import buffer +import twtio +import config +import parser + +let clientInstance = newHttpClient() +proc loadRemotePage*(url: string): string = + return clientInstance.getContent(url) + +proc loadLocalPage*(url: string): string = + return readFile(url) + +proc getRemotePage*(url: string): Stream = + return clientInstance.get(url).bodyStream + +proc getLocalPage*(url: string): Stream = + return newFileStream(url, fmRead) + +proc getPageUri(uri: Uri): Stream = + var moduri = uri + moduri.anchor = "" + if uri.scheme == "" or uri.scheme == "file": + return getLocalPage($moduri) + else: + return getRemotePage($moduri) + +var buffers: seq[Buffer] + +proc main*() = + if paramCount() != 1: + eprint "Invalid parameters. Usage:\ntwt " + quit(1) + if not readConfig("config"): + eprint "Failed to read keymap, falling back to default" + let attrs = getTermAttributes() + let buffer = newBuffer(attrs) + let uri = parseUri(paramStr(1)) + buffers.add(buffer) + buffer.document = parseHtml(getPageUri(uri)) + buffer.setLocation(uri) + buffer.renderHtml() + var lastUri = uri + while displayPage(attrs, buffer): + statusMsg("Loading...", buffer.height) + var newUri = buffer.document.location + lastUri.anchor = "" + newUri.anchor = "" + if $lastUri != $newUri: + buffer.clearBuffer() + if uri.scheme == "" and uri.path == "" and uri.anchor != "": + discard + else: + buffer.document = parseHtml(getPageUri(buffer.document.location)) + buffer.renderHtml() + lastUri = newUri + +main() +#parseCSS(newFileStream("default.css", fmRead)) diff --git a/src/parser.nim b/src/parser.nim new file mode 100644 index 00000000..724d2b30 --- /dev/null +++ b/src/parser.nim @@ -0,0 +1,555 @@ +import streams +import unicode +import strutils +import tables +import json + +import twtio +import enums +import twtstr +import dom +import radixtree +import style +import entity + +type + HTMLParseState = object + closed: bool + parents: seq[Node] + parsedNode: Node + a: string + b: string + attrs: seq[string] + in_comment: bool + in_script: bool + in_style: bool + in_noscript: bool + parentNode: Node + textNode: Text + + CSSParseState = object + in_comment: bool + +#func newHtmlElement(tagType: TagType, parentNode: Node): HtmlElement = +# case tagType +# of TAG_INPUT: result = new(HtmlInputElement) +# of TAG_A: result = new(HtmlAnchorElement) +# of TAG_SELECT: result = new(HtmlSelectElement) +# of TAG_OPTION: result = new(HtmlOptionElement) +# else: result = new(HtmlElement) +# +# result.nodeType = ELEMENT_NODE +# result.tagType = tagType +# result.parentNode = parentNode +# if parentNode.isElemNode(): +# result.parentElement = HtmlElement(parentNode) +# +# if tagType in DisplayInlineTags: +# result.display = DISPLAY_INLINE +# elif tagType in DisplayBlockTags: +# result.display = DISPLAY_BLOCK +# elif tagType in DisplayInlineBlockTags: +# result.display = DISPLAY_INLINE_BLOCK +# elif tagType == TAG_LI: +# result.display = DISPLAY_LIST_ITEM +# else: +# result.display = DISPLAY_NONE +# +# case tagType +# of TAG_CENTER: +# result.centered = true +# of TAG_B: +# result.bold = true +# of TAG_I: +# result.italic = true +# of TAG_U: +# result.underscore = true +# of TAG_HEAD: +# result.hidden = true +# of TAG_STYLE: +# result.hidden = true +# of TAG_SCRIPT: +# result.hidden = true +# of TAG_OPTION: +# result.hidden = true #TODO +# of TAG_PRE, TAG_TD, TAG_TH: +# result.margin = 1 +# of TAG_UL, TAG_OL: +# result.indent = 2 +# result.margin = 1 +# of TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6: +# result.bold = true +# result.margin = 1 +# of TAG_A: +# result.islink = true +# of TAG_INPUT: +# HtmlInputElement(result).size = 20 +# else: discard +# +# if parentNode.isElemNode(): +# let parent = HtmlElement(parentNode) +# result.centered = result.centered or parent.centered +# result.bold = result.bold or parent.bold +# result.italic = result.italic or parent.italic +# result.underscore = result.underscore or parent.underscore +# result.hidden = result.hidden or parent.hidden +# result.islink = result.islink or parent.islink + +func inputSize*(str: string): int = + if str.len == 0: + return 20 + for c in str: + if not c.isDigit: + return 20 + return str.parseInt() + +#w3m's getescapecmd and parse_tag, transpiled to nim. +#(C) Copyright 1994-2002 by Akinori Ito +#(C) Copyright 2002-2011 by Akinori Ito, Hironori Sakamoto, Fumitoshi Ukai +# +#Use, modification and redistribution of this software is hereby granted, +#provided that this entire copyright notice is included on any copies of +#this software and applications and derivations thereof. +# +#This software is provided on an "as is" basis, without warranty of any +#kind, either expressed or implied, as to any matter including, but not +#limited to warranty of fitness of purpose, or merchantability, or +#results obtained from use of this software. +proc getescapecmd(buf: string, at: var int): string = + var i = at + + if buf[i] == '#': #num + inc i + var num: int + if buf[i].tolower() == 'x': #hex + inc i + if not isdigit(buf[i]): + at = i + return "" + + num = hexValue(buf[i]) + inc i + while i < buf.len and hexValue(buf[i]) != -1: + num *= 0x10 + num += hexValue(buf[i]) + inc i + else: #dec + if not isDigit(buf[i]): + at = i + return "" + + num = decValue(buf[i]) + inc i + while i < buf.len and isDigit(buf[i]): + num *= 10 + num += decValue(buf[i]) + inc i + + if buf[i] == ';': + inc i + at = i + return $(Rune(num)) + elif not isAlphaAscii(buf[i]): + return "" + + var n = 0 + var s = "" + while true: + s &= buf[i] + if not entityMap.hasPrefix(s, n): + break + let pn = n + n = entityMap[s, n] + if n != pn: + s = "" + inc i + + if entityMap.nodes[n].leaf: + at = i + return entityMap.nodes[n].value + + return "" + +type + DOMParsedTag = object + tagid: TagType + attrs: Table[string, string] + open: bool + +proc parse_tag(buf: string, at: var int): DOMParsedTag = + var tag = DOMParsedTag() + tag.open = true + + #Parse tag name + var tagname = "" + inc at + if buf[at] == '/': + inc at + tag.open = false + at = skipBlanks(buf, at) + + while at < buf.len and not buf[at].isWhitespace() and not (tag.open and buf[at] == '/') and buf[at] != '>': + tagname &= buf[at].tolower() + at += buf.runeLenAt(at) + + tag.tagid = tagType(tagname) + at = skipBlanks(buf, at) + + while at < buf.len and buf[at] != '>': + var value = "" + var attrname = "" + while at < buf.len and buf[at] != '=' and not buf[at].isWhitespace() and buf[at] != '>': + attrname &= buf[at].tolower() + at += buf.runeLenAt(at) + + at = skipBlanks(buf, at) + if buf[at] == '=': + inc at + at = skipBlanks(buf, at) + if at < buf.len and (buf[at] == '"' or buf[at] == '\''): + let startc = buf[at] + inc at + while at < buf.len and buf[at] != startc: + var r: Rune + fastRuneAt(buf, at, r) + if r == Rune('&'): + value &= getescapecmd(buf, at) + else: + value &= $r + if at < buf.len: + inc at + elif at < buf.len: + while at < buf.len and not buf[at].isWhitespace() and buf[at] != '>': + value &= buf[at] + at += buf.runeLenAt(at) + + if attrname.len > 0: + tag.attrs[attrname] = value + + while at < buf.len and buf[at] != '>': + at += buf.runeLenAt(at) + + if at < buf.len and buf[at] == '>': + inc at + return tag + +proc insertNode(parent: Node, node: Node) = + parent.childNodes.add(node) + + if parent.firstChild == nil: + parent.firstChild = node + + parent.lastChild = node + + if parent.childNodes.len > 1: + let prevSibling = parent.childNodes[^1] + prevSibling.nextSibling = node + node.previousSibling = prevSibling + + node.parentNode = parent + if parent.nodeType == ELEMENT_NODE: + node.parentElement = Element(parent) + + if parent.ownerDocument != nil: + node.ownerDocument = parent.ownerDocument + elif parent.nodeType == DOCUMENT_NODE: + node.ownerDocument = Document(parent) + +proc processDocumentStartNode(state: var HTMLParseState, newNode: Node) = + insertNode(state.parentNode, newNode) + state.parentNode = newNode + +proc processDocumentEndNode(state: var HTMLParseState) = + if state.parentNode == nil or state.parentNode.parentNode == nil: + return + state.parentNode = state.parentNode.parentNode + +proc processDocumentText(state: var HTMLParseState) = + if state.textNode == nil: + state.textNode = newText() + + processDocumentStartNode(state, state.textNode) + processDocumentEndNode(state) + +proc processDocumentStartElement(state: var HTMLParseState, element: Element, tag: DOMParsedTag) = + for k, v in tag.attrs: + element.attributes[k] = element.newAttr(k, v) + + element.id = element.getAttrValue("id") + if element.attributes.hasKey("class"): + for w in unicode.split(element.attributes["class"].value, Rune(' ')): + element.classList.add(w) + + case element.tagType + of TAG_SCRIPT: + state.in_script = true + of TAG_NOSCRIPT: + state.in_noscript = true + of TAG_STYLE: + state.in_style = true + of TAG_SELECT: + HTMLSelectElement(element).name = element.getAttrValue("name") + HTMLSelectElement(element).value = element.getAttrValue("value") + of TAG_INPUT: + HTMLInputElement(element).value = element.getAttrValue("value") + HTMLInputElement(element).itype = element.getAttrValue("type").inputType() + HTMLInputElement(element).size = element.getAttrValue("size").inputSize() + of TAG_A: + HTMLAnchorElement(element).href = element.getAttrValue("href") + of TAG_OPTION: + HTMLOptionElement(element).value = element.getAttrValue("href") + else: discard + + if state.parentNode.nodeType == ELEMENT_NODE: + case element.tagType + of TAG_LI, TAG_P: + if Element(state.parentNode).tagType == element.tagType: + processDocumentEndNode(state) + of TAG_H1: + HTMLHeadingElement(element).rank = 1 + of TAG_H2: + HTMLHeadingElement(element).rank = 2 + of TAG_H3: + HTMLHeadingElement(element).rank = 3 + of TAG_H4: + HTMLHeadingElement(element).rank = 4 + of TAG_H5: + HTMLHeadingElement(element).rank = 5 + of TAG_H6: + HTMLHeadingElement(element).rank = 6 + else: discard + + processDocumentStartNode(state, element) + + if element.tagType in VoidTagTypes: + processDocumentEndNode(state) + +proc processDocumentEndElement(state: var HTMLParseState, tag: DOMParsedTag) = + if tag.tagid in VoidTagTypes: + return + if state.parentNode.nodeType == ELEMENT_NODE: + if Element(state.parentNode).tagType in {TAG_LI, TAG_P}: + processDocumentEndNode(state) + + processDocumentEndNode(state) + +proc processDocumentTag(state: var HTMLParseState, tag: DOMParsedTag) = + if state.in_script: + if tag.tagid == TAG_SCRIPT: + state.in_script = false + else: + return + + if state.in_style: + if tag.tagid == TAG_STYLE: + state.in_style = false + else: + return + + if state.in_noscript: + if tag.tagid == TAG_NOSCRIPT: + state.in_noscript = false + else: + return + + if tag.open: + processDocumentStartElement(state, newHtmlElement(tag.tagid), tag) + else: + processDocumentEndElement(state, tag) + +proc processDocumentPart(state: var HTMLParseState, buf: string) = + var at = 0 + var max = 0 + var was_script = false + + max = buf.len + + while at < max: + case buf[at] + of '&': + inc at + let p = getescapecmd(buf, at) + if state.in_comment: + CharacterData(state.parentNode).data &= p + else: + processDocumentText(state) + state.textNode.data &= p + of '<': + if state.in_comment: + CharacterData(state.parentNode).data &= buf[at] + inc at + else: + var p = at + inc p + if p < max and buf[p] == '!': + inc p + if p < max and buf[p] == '-': + inc p + if p < max and buf[p] == '-': + inc p + at = p + state.in_comment = true + processDocumentStartNode(state, newComment()) + if state.textNode != nil: + state.textNode.rawtext = state.textNode.getRawText() + state.textNode = nil + + if not state.in_comment: + if state.textNode != nil: + state.textNode.rawtext = state.textNode.getRawText() + state.textNode = nil + p = at + var tag = parse_tag(buf, at) + was_script = state.in_script + + processDocumentTag(state, tag) +# if (was_script) { +# if (state->in_script) { +# ptr = p; +# processDocumentText(&state->parentNode, &state->textNode); +# Strcat_char(((CharacterData *)state->textNode)->data, *ptr++); +# } else if (buffer->javascript_enabled) { +# loadJSToBuffer(buffer, childTextContentNode(state->parentNode->lastChild)->ptr, "", state->document); +# } +# } + elif buf[at] == '-' and state.in_comment: + var p = at + inc p + if p < max and buf[p] == '-': + inc p + if p < max and buf[p] == '>': + inc p + at = p + state.in_comment = false + processDocumentEndNode(state) + + if state.in_comment: + CharacterData(state.parentNode).data &= buf[at] + inc at + else: + var r: Rune + fastRuneAt(buf, at, r) + if state.in_comment: + CharacterData(state.parentNode).data &= $r + else: + processDocumentText(state) + state.textNode.data &= $r + +proc parseHtml*(inputStream: Stream): Document = + let document = newDocument() + + var state = HTMLParseState() + state.parentNode = document + + var till_when = false + + var buf = "" + var lineBuf: string + while not inputStream.atEnd(): + lineBuf = inputStream.readLine() + buf &= lineBuf + + var at = 0 + while at < lineBuf.len: + case lineBuf[at] + of '<': + till_when = true + of '>': + till_when = false + else: discard + at += lineBuf.runeLenAt(at) + + if till_when: + continue + + processDocumentPart(state, buf) + buf = "" + + inputStream.close() + return document + +proc consumeCSSString(state: var CSSParseState, line: seq[Rune], at: var int): CSSToken = + var s: seq[Rune] + let ending = line[at] + inc at + if at >= line.len: + return CSSToken(tokenType: CSS_STRING_TOKEN, value: s) + + while line[at] != ending: + inc at + + if at >= line.len: + return CSSToken(tokenType: CSS_STRING_TOKEN, value: s) + + s &= line[at] + + case line[at] + of Rune('\n'): + return CSSToken(tokenType: CSS_BAD_STRING_TOKEN) + of Rune('\\'): + inc at + if at > line.len: + break + var num = hexValue(line[at]) + if num != -1: + let ca = at + inc at + while at < line.len and hexValue(line[at]) != -1 and ca - at <= 5: + num *= 0x10 + num += hexValue(line[at]) + inc at + if num == 0 or num > 0x10FFFF or num in {0xD800..0xDFFF}: + s &= Rune(0xFFFD) + else: + s &= Rune(num) + else: discard + +proc consumeCSSNumberSign(state: var CSSParseState, line: seq[Rune], at: var int): CSSToken = + inc at + if at < line.len: + if isNameCodePoint(line[at]): + discard + else: + discard + + +proc consumeCSSToken(state: var CSSParseState, line: seq[Rune], at: var int): CSSToken = + case line[at] + of Rune('\n'), Rune('\t'), Rune(' '): + while at < line.len and line[at].isWhitespace(): + inc at + return CSSToken(tokenType: CSS_WHITESPACE_TOKEN) + of Rune('"'): + return consumeCSSString(state, line, at) + of Rune('#'): + return consumeCSSNumberSign(state, line, at) + else: inc at + +proc tokenizeCSS*(inputStream: Stream): seq[CSSToken] = + var line: seq[Rune] + var state: CSSParseState + while not inputStream.atEnd(): + line = inputStream.readLine().toRunes() + var cline: seq[Rune] = @[] + var lfc = false + for r in line: + case r + of Rune('\r'), Rune('\f'), Rune('\n'): + lfc = true + of Rune(0), Rune(0xD800)..Rune(0xDFFF): + cline &= Rune(0xFFFD) + else: + if lfc: + cline &= Rune('\n') + cline &= r + + cline &= Rune('\n') + var lat = 0 + while lat < cline.len: + result.add(consumeCSSToken(state, cline, lat)) + + inputStream.close() + +proc parseCSS*(inputStream: Stream) = + for t in tokenizeCSS(inputStream): + eprint t.tokenType diff --git a/src/radixtree.nim b/src/radixtree.nim new file mode 100644 index 00000000..b04e1c22 --- /dev/null +++ b/src/radixtree.nim @@ -0,0 +1,151 @@ +# Radix tree implementation, with some caveats: +# * insertion takes forever, so try to insert only during compile-time +# * it isn't that much faster than a hash table, even when used for e.g. parsing + +import tables +import strutils +import json + +type + RadixNode[T] = object + children*: Table[string, int] + case leaf*: bool + of true: value*: T + of false: discard + + RadixTree*[T] = object + nodes*: seq[RadixNode[T]] + +func newRadixTree*[T](): RadixTree[T] = + result.nodes.add(RadixNode[T](leaf: false)) + +proc `[]=`*[T](tree: var RadixTree[T], key: string, value: T) = + var n = 0 + var p = 0 + var i = 0 + var j = 0 + var s = "" + var t = "" + var nodeKey = "" + # find last matching node + while i < key.len: + s &= key[i] + inc i + if s in tree.nodes[n].children: + p = n + n = tree.nodes[n].children[s] + t &= s + j = i + nodeKey = s + s = "" + + for k in tree.nodes[n].children.keys: + if s.len > 0 and k.startsWith(s[0]): + p = n + n = tree.nodes[n].children[k] + t &= k + nodeKey = k + break + + # if first node, just add normally + if n == 0: + tree.nodes.add(RadixNode[T](leaf: true, value: value)) + tree.nodes[n].children[key] = int(tree.nodes.len - 1) + else: + i = 0 + var conflict = false + # compare new key with the one we found so far + while i < t.len and i < key.len: + if key[i] == t[i]: + inc i + else: + conflict = true + break + + if conflict: + # conflict somewhere, so: + # * add new non-leaf to parent + # * add old to non-leaf + # * add new to non-leaf + # * remove old from parent + assert(i != 0) + + tree.nodes[p].children[key.substr(j, i - 1)] = int(tree.nodes.len) + tree.nodes.add(RadixNode[T](leaf: false)) + tree.nodes[^1].children[t.substr(i)] = n + tree.nodes[^1].children[key.substr(i)] = int(tree.nodes.len) + tree.nodes.add(RadixNode[T](leaf: true, value: value)) + tree.nodes[p].children.del(nodeKey) + else: # new is either substr of old or old is substr of new + # new matches a node, so replace + if key.len == t.len: + let children = tree.nodes[n].children + tree.nodes[n] = RadixNode[T](leaf: true, value: value) + tree.nodes[n].children = children + elif i == j: + # new is longer than the old, so add child to old + tree.nodes[n].children[key.substr(i)] = int(tree.nodes.len) + tree.nodes.add(RadixNode[T](leaf: true, value: value)) + elif i > 0: + # new is shorter than old, so: + # * add new to parent + # * add old to new + # * remove old from parent + tree.nodes[p].children[key.substr(j, i - 1)] = int(tree.nodes.len) + tree.nodes.add(RadixNode[T](leaf: true, value: value)) + tree.nodes[^1].children[t.substr(i)] = n + tree.nodes[p].children.del(nodeKey) + +func `[]`*[T](tree: RadixTree[T], key: string, at: int = 0): int = + return tree.nodes[at].children.getOrDefault(key, at) + +func hasPrefix*[T](tree: RadixTree[T], prefix: string, at: int = 0): bool = + var n = at + var i = 0 + var j = 0 + var s = "" + while i < prefix.len: + s &= prefix[i] + inc i + if s in tree.nodes[n].children: + n = tree.nodes[n].children[s] + j = i + + if j == prefix.len: + return true + + for k in tree.nodes[n].children.keys: + if prefix.len - j < k.len and k[0] == prefix[j]: + i = 1 + inc j + while j < prefix.len: + inc i + inc j + if k[i] != k[j]: + return false + return true + + return false + +#tests +#var tree = newRadixTree[string]() +#tree.insert("hb", "abc") +#tree.insert("hi", "second") +#tree.insert("hia", "second") +#tree.insert("hia", "third") +#tree.insert("hiahhhooo", "two point fifth") +#tree.insert("hiahhho", "two point sixth") +#assert(tree.hasPrefix("h")) +#assert(tree.hasPrefix("hi")) +#assert(not tree.hasPrefix("hio")) +#assert(tree.hasPrefix("hiah")) +#assert(tree.hasPrefix("hiahhho")) +#assert(tree.hasPrefix("hiahhhooo")) +#assert(tree.lookup("hi", "error") != "error") +#assert(tree.lookup("hb", "error") != "error") +#assert(tree.lookup("hio", "error") == "error") +#assert(tree.lookup("hia", "error") != "error") +#assert(tree.lookup("hiahhhooo", "error") != "error") +#assert(tree.lookup("hiahhho", "error") != "error") +#assert(tree.lookup("hiahhhoo", "error") == "error") +#assert(tree.lookup("h", "error") == "error") diff --git a/src/style.nim b/src/style.nim new file mode 100644 index 00000000..7de1e767 --- /dev/null +++ b/src/style.nim @@ -0,0 +1,42 @@ +import enums +import unicode + +type + CSS2Properties* = ref object + rawtext*: string + fmttext*: seq[string] + x*: int + y*: int + ex*: int + ey*: int + width*: int + height*: int + hidden*: bool + before*: CSS2Properties + after*: CSS2Properties + margintop*: int + marginbottom*: int + marginleft*: int + marginright*: int + margin*: int + centered*: bool + display*: DisplayType + bold*: bool + italic*: bool + underscore*: bool + islink*: bool + selected*: bool + indent*: int + + CSSToken* = object + case tokenType*: CSSTokenType + of CSS_IDENT_TOKEN, CSS_FUNCTION_TOKEN, CSS_AT_KEYWORD_TOKEN, + CSS_HASH_TOKEN, CSS_STRING_TOKEN, CSS_URL_TOKEN: + value*: seq[Rune] + tflaga*: bool #id / unrestricted + of CSS_DELIM_TOKEN: + rvalue*: Rune + of CSS_NUMBER_TOKEN, CSS_PERCENTAGE_TOKEN, CSS_DIMENSION_TOKEN: + ivalue*: int + tflagb*: bool #integer / number + else: discard diff --git a/src/termattrs.nim b/src/termattrs.nim new file mode 100644 index 00000000..d49800ae --- /dev/null +++ b/src/termattrs.nim @@ -0,0 +1,11 @@ +import terminal + +type + TermAttributes* = object + termWidth*: int + termHeight*: int + +proc getTermAttributes*(): TermAttributes = + let attrs = TermAttributes(termWidth: terminalWidth(), + termHeight: terminalHeight()) + return attrs diff --git a/src/twtio.nim b/src/twtio.nim new file mode 100644 index 00000000..0fdbed7c --- /dev/null +++ b/src/twtio.nim @@ -0,0 +1,180 @@ +import terminal +import tables +import unicode + +import twtstr +import config +import radixtree + +template print*(s: varargs[string, `$`]) = + for x in s: + stdout.write(x) + +template printesc*(s: string) = + for r in s.runes: + if r.isControlChar(): + stdout.write(('^' & $($r)[0].getControlLetter()) + .ansiFgColor(fgBlue).ansiStyle(styleBright).ansiReset()) + else: + stdout.write($r) + +template eprint*(s: varargs[string, `$`]) = {.cast(noSideEffect).}: + var a = false + for x in s: + if not a: + a = true + else: + stderr.write(' ') + stderr.write(x) + stderr.write('\n') + +proc termGoto*(x: int, y: int) = + setCursorPos(stdout, x, y) + +proc getNormalAction*(s: string): TwtAction = + if normalActionRemap.hasKey(s): + return normalActionRemap[s] + return NO_ACTION + +proc getLinedAction*(s: string): TwtAction = + if linedActionRemap.hasKey(s): + return linedActionRemap[s] + return NO_ACTION + +proc readLine*(prompt: string, current: var string, termwidth: int): bool = + var news = current.toRunes() + let maxlen = termwidth - prompt.len + var s = "" + var feedNext = false + var escNext = false + var comp = false + var compi = 0 + var compa = 0 + var comps = "" + var cursor = news.len + var shift = 0 + while true: + let rl = news.len + if cursor < shift: + shift = max(cursor - 1, 0) + else: + while news.substr(shift, shift + cursor).width() > maxlen - 1: + shift += news[^1].width() + + eraseLine() + printesc(prompt & $news.substr(shift, shift + maxlen - 1)) + + print('\r') + cursorForward(prompt.len + news.substr(shift, cursor).width()) + + if not feedNext: + s = "" + else: + feedNext = false + let c = getch() + s &= c + var action = getLinedAction(s) + if escNext: + action = NO_ACTION + case action + of ACTION_LINED_CANCEL: + return false + of ACTION_LINED_SUBMIT: + current = $news + return true + of ACTION_LINED_BACKSPACE: + if cursor > 0: + news = news.substr(0, cursor - 1) & news.substr(cursor) + dec cursor + of ACTION_LINED_DELETE: + if cursor > 0 and cursor < rl: + news = news.substr(0, cursor) & news.substr(cursor + 1) + of ACTION_LINED_ESC: + escNext = true + of ACTION_LINED_CLEAR: + news = news.substr(cursor) + cursor = 0 + of ACTION_LINED_KILL: + news = news.substr(0, cursor) + of ACTION_LINED_BACK: + if cursor > 0: + dec cursor + of ACTION_LINED_FORWARD: + if cursor < rl: + inc cursor + of ACTION_LINED_PREV_WORD: + while cursor > 0: + dec cursor + if news[cursor].breaksWord(): + break + of ACTION_LINED_NEXT_WORD: + while cursor < rl: + inc cursor + if cursor < rl: + if news[cursor].breaksWord(): + break + of ACTION_LINED_KILL_WORD: + var chars = 0 + while cursor > chars: + inc chars + if news[cursor - chars].breaksWord(): + break + if chars > 0: + news = news.substr(0, cursor - chars) & news.substr(cursor) + cursor -= chars + of ACTION_LINED_COMPOSE_ON: + comp = true + compi = 0 + compa = 0 + comps = "" + of ACTION_LINED_COMPOSE_OFF: + comp = false + compi = 0 + compa = 0 + comps = "" + of ACTION_LINED_COMPOSE_TOGGLE: + comp = not comp + compi = 0 + compa = 0 + comps = "" + of ACTION_FEED_NEXT: + feedNext = true + elif comp: + comps &= c + let n = composeRemap[comps, compi] + if n != compi: + compi = n + compa += comps.len + comps = "" + if composeRemap.hasPrefix(comps, compi) and composeRemap.nodes[n].children.len > 0: + feedNext = true + else: + var cs = "" + if composeRemap.nodes[compi].leaf: + cs = composeRemap.nodes[compi].value + else: + cs = s.substr(0, compa - 1) + comps = s.substr(compa) + if not composeRemap.hasPrefix(comps, 0): + cs &= comps + comps = "" + + news = news.substr(0, cursor) & cs.toRunes() & news.substr(cursor) + cursor += cs.runeLen() + compi = 0 + compa = 0 + elif validateUtf8(s) == -1: + var cs = "" + for c in s: + if not c.isControlChar(): + cs &= c + elif escNext: + cs &= c + escNext = false + escNext = false + if cs.len == 0: + continue + news = news.substr(0, cursor) & cs.toRunes() & news.substr(cursor) + cursor += cs.runeLen() + else: + feedNext = true diff --git a/src/twtstr.nim b/src/twtstr.nim new file mode 100644 index 00000000..52db36cf --- /dev/null +++ b/src/twtstr.nim @@ -0,0 +1,423 @@ +import terminal +import strutils +import unicode + +func ansiStyle*(str: string, style: Style): seq[string] = + result &= ansiStyleCode(style) + result &= str + +func ansiFgColor*(str: string, color: ForegroundColor): seq[string] = + result &= ansiForegroundColorCode(color) + result &= str + +func ansiReset*(str: string): seq[string] = + result &= str + result &= ansiResetCode + +func ansiStyle*(str: seq[string], style: Style): seq[string] = + return ansiStyleCode(style) & str + +func ansiFgColor*(str: seq[string], color: ForegroundColor): seq[string] = + return ansiForegroundColorCode(color) & str + +func ansiReset*(str: seq[string]): seq[string] = + return str & ansiResetCode + +func maxString*(str: string, max: int): string = + if max < str.runeLen(): + return str.runeSubstr(0, max - 2) & "$" + return str + +func fitValueToSize*(str: string, size: int): string = + if str.runeLen < size: + return str & ' '.repeat(size - str.runeLen) + return str.maxString(size) + +func buttonFmt*(str: string): seq[string] = + return "[".ansiFgColor(fgRed) & str.ansiFgColor(fgRed).ansiReset() & "]".ansiFgColor(fgRed).ansiReset() + +func buttonFmt*(str: seq[string]): seq[string] = + return "[".ansiFgColor(fgRed) & str.ansiFgColor(fgRed).ansiReset() & "]".ansiFgColor(fgRed).ansiReset() + +func buttonRaw*(str: string): string = + return "[" & str & "]" + +func remove*(str: string, c: string): string = + let rem = c.toRunes()[0] + for rune in str.runes: + if rem != rune: + result &= $rune + +func isWhitespace*(c: char): bool = + case c + of ' ', '\n', '\r', '\t', '\f': return true + else: return false + +func isControlChar*(c: char): bool = + case c + of chr(0x00)..chr(0x1F): return true + of chr(0x7F): return true + else: return false + +func isControlChar*(r: Rune): bool = + case r + of Rune(0x00)..Rune(0x1F): return true + of Rune(0x7F): return true + else: return false + +func genControlCharMap*(): string = + for c in low(char)..high(char): + if c >= 'a': + result &= char(int(c) - int('a') + 1) + elif c == '?': + result &= char(127) + else: + result &= char(0) + +const controlCharMap = genControlCharMap() + +func getControlChar*(c: char): char = + return controlCharMap[int(c)] + +func getControlLetter*(c: char): char = + if int(c) <= 0x1F: + return char(int(c) + int('A') - 1) + elif c == '\x7F': + return '?' + assert(false) + +func findChar*(str: string, c: char, start: int = 0): int = + var i = start + while i < str.len: + if str[i] == c: + return i + inc i + return -1 + +func findChar*(str: string, c: Rune, start: int = 0): int = + var i = start + var n = i + while i < str.runeLen(): + var r: Rune + fastRuneAt(str, n, r) + if r == c: + return i + i = n + return -1 + +func getLowerChars*(): string = + result = "" + for i in 0..255: + if chr(i) >= 'A' and chr(i) <= 'Z': + result &= chr(i + 32) + else: + result &= chr(i) + +const lowerChars = getLowerChars() + +func tolower*(c: char): char = + return lowerChars[int(c)] + +const breakWord = [ + Rune('\n'), Rune('/'), Rune('\\'), Rune(' '), Rune('&'), Rune('='), + Rune('?'), Rune('.'), Rune(';') +] + +func genHexCharMap(): seq[int] = + for i in 0..255: + case chr(i) + of '0'..'9': result &= i - ord('0') + of 'a'..'f': result &= i - ord('a') + 10 + of 'A'..'F': result &= i - ord('A') + 10 + else: result &= -1 + +func genDecCharMap(): seq[int] = + for i in 0..255: + case chr(i) + of '0'..'9': result &= i - ord('0') + else: result &= -1 + +const hexCharMap = genHexCharMap() +const decCharMap = genDecCharMap() + +func hexValue*(c: char): int = + return hexCharMap[int(c)] + +func decValue*(c: char): int = + return decCharMap[int(c)] + +func isAscii*(r: Rune): bool = + return int(r) <= int(high(char)) + +func hexValue*(r: Rune): int = + if isAscii(r): + return hexValue(char(r)) + return -1 + +func decValue*(r: Rune): int = + if isAscii(r): + return decValue(char(r)) + return -1 + +func breaksWord*(r: Rune): bool = + return r in breakWord + +func isAlphaAscii*(r: Rune): bool = + return isAscii(r) and isAlphaAscii(char(r)) + +func isDigitAscii*(r: Rune): bool = + return isAscii(r) and isDigit(char(r)) + +func isNameStartCodePoint*(r: Rune): bool = + return not isAscii(r) or r == Rune('_') or isAlphaAscii(r) + +func isNameCodePoint*(r: Rune): bool = + return isNameStartCodePoint(r) or isDigitAscii(r) or r == Rune('-') + +func substr*(s: seq[Rune], i: int, j: int): seq[Rune] = + if s.len == 0: + return @[] + return s[min(high(s), i)..min(high(s), j - 1)] + +func substr*(s: seq[Rune], i: int): seq[Rune] = + if i >= high(s) or s.len == 0: + return @[] + return s[min(high(s), i)..high(s)] + +#Measure length of rune. From https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + +#auxiliary function for binary search in interval table +func bisearch(ucs: Rune, table: openarray[(int, int)]): bool = + var max = table.high + var min = 0 + var mid: int + + if int(ucs) < table[0][0] or int(ucs) > table[max][1]: + return false + + while max >= min: + mid = (min + max) div 2 + if int(ucs) > table[mid][1]: + min = mid + 1 + elif int(ucs) < table[mid][0]: + max = mid - 1 + else: + return true + return false + +#The following two functions define the column width of an ISO 10646 +#character as follows: +# +# - The null character (U+0000) has a column width of 0. +# +# - Other C0/C1 control characters and DEL will lead to a return +# value of 2. +# +# - Non-spacing and enclosing combining characters (general +# category code Mn or Me in the Unicode database) have a +# column width of 0. +# +# - SOFT HYPHEN (U+00AD) has a column width of 1. +# +# - Other format characters (general category code Cf in the Unicode +# database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. +# +# - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) +# have a column width of 0. +# +# - Spacing characters in the East Asian Wide (W) or East Asian +# Full-width (F) category as defined in Unicode Technical +# Report #11 have a column width of 2. +# +# - All remaining characters (including all printable +# ISO 8859-1 and WGL4 characters, Unicode control characters, +# etc.) have a column width of 1. +# +#This implementation assumes that wchar_t characters are encoded +#in ISO 10646. +# + +const combining = [ + ( 0x0300, 0x036F ), ( 0x0483, 0x0486 ), ( 0x0488, 0x0489 ), + ( 0x0591, 0x05BD ), ( 0x05BF, 0x05BF ), ( 0x05C1, 0x05C2 ), + ( 0x05C4, 0x05C5 ), ( 0x05C7, 0x05C7 ), ( 0x0600, 0x0603 ), + ( 0x0610, 0x0615 ), ( 0x064B, 0x065E ), ( 0x0670, 0x0670 ), + ( 0x06D6, 0x06E4 ), ( 0x06E7, 0x06E8 ), ( 0x06EA, 0x06ED ), + ( 0x070F, 0x070F ), ( 0x0711, 0x0711 ), ( 0x0730, 0x074A ), + ( 0x07A6, 0x07B0 ), ( 0x07EB, 0x07F3 ), ( 0x0901, 0x0902 ), + ( 0x093C, 0x093C ), ( 0x0941, 0x0948 ), ( 0x094D, 0x094D ), + ( 0x0951, 0x0954 ), ( 0x0962, 0x0963 ), ( 0x0981, 0x0981 ), + ( 0x09BC, 0x09BC ), ( 0x09C1, 0x09C4 ), ( 0x09CD, 0x09CD ), + ( 0x09E2, 0x09E3 ), ( 0x0A01, 0x0A02 ), ( 0x0A3C, 0x0A3C ), + ( 0x0A41, 0x0A42 ), ( 0x0A47, 0x0A48 ), ( 0x0A4B, 0x0A4D ), + ( 0x0A70, 0x0A71 ), ( 0x0A81, 0x0A82 ), ( 0x0ABC, 0x0ABC ), + ( 0x0AC1, 0x0AC5 ), ( 0x0AC7, 0x0AC8 ), ( 0x0ACD, 0x0ACD ), + ( 0x0AE2, 0x0AE3 ), ( 0x0B01, 0x0B01 ), ( 0x0B3C, 0x0B3C ), + ( 0x0B3F, 0x0B3F ), ( 0x0B41, 0x0B43 ), ( 0x0B4D, 0x0B4D ), + ( 0x0B56, 0x0B56 ), ( 0x0B82, 0x0B82 ), ( 0x0BC0, 0x0BC0 ), + ( 0x0BCD, 0x0BCD ), ( 0x0C3E, 0x0C40 ), ( 0x0C46, 0x0C48 ), + ( 0x0C4A, 0x0C4D ), ( 0x0C55, 0x0C56 ), ( 0x0CBC, 0x0CBC ), + ( 0x0CBF, 0x0CBF ), ( 0x0CC6, 0x0CC6 ), ( 0x0CCC, 0x0CCD ), + ( 0x0CE2, 0x0CE3 ), ( 0x0D41, 0x0D43 ), ( 0x0D4D, 0x0D4D ), + ( 0x0DCA, 0x0DCA ), ( 0x0DD2, 0x0DD4 ), ( 0x0DD6, 0x0DD6 ), + ( 0x0E31, 0x0E31 ), ( 0x0E34, 0x0E3A ), ( 0x0E47, 0x0E4E ), + ( 0x0EB1, 0x0EB1 ), ( 0x0EB4, 0x0EB9 ), ( 0x0EBB, 0x0EBC ), + ( 0x0EC8, 0x0ECD ), ( 0x0F18, 0x0F19 ), ( 0x0F35, 0x0F35 ), + ( 0x0F37, 0x0F37 ), ( 0x0F39, 0x0F39 ), ( 0x0F71, 0x0F7E ), + ( 0x0F80, 0x0F84 ), ( 0x0F86, 0x0F87 ), ( 0x0F90, 0x0F97 ), + ( 0x0F99, 0x0FBC ), ( 0x0FC6, 0x0FC6 ), ( 0x102D, 0x1030 ), + ( 0x1032, 0x1032 ), ( 0x1036, 0x1037 ), ( 0x1039, 0x1039 ), + ( 0x1058, 0x1059 ), ( 0x1160, 0x11FF ), ( 0x135F, 0x135F ), + ( 0x1712, 0x1714 ), ( 0x1732, 0x1734 ), ( 0x1752, 0x1753 ), + ( 0x1772, 0x1773 ), ( 0x17B4, 0x17B5 ), ( 0x17B7, 0x17BD ), + ( 0x17C6, 0x17C6 ), ( 0x17C9, 0x17D3 ), ( 0x17DD, 0x17DD ), + ( 0x180B, 0x180D ), ( 0x18A9, 0x18A9 ), ( 0x1920, 0x1922 ), + ( 0x1927, 0x1928 ), ( 0x1932, 0x1932 ), ( 0x1939, 0x193B ), + ( 0x1A17, 0x1A18 ), ( 0x1B00, 0x1B03 ), ( 0x1B34, 0x1B34 ), + ( 0x1B36, 0x1B3A ), ( 0x1B3C, 0x1B3C ), ( 0x1B42, 0x1B42 ), + ( 0x1B6B, 0x1B73 ), ( 0x1DC0, 0x1DCA ), ( 0x1DFE, 0x1DFF ), + ( 0x200B, 0x200F ), ( 0x202A, 0x202E ), ( 0x2060, 0x2063 ), + ( 0x206A, 0x206F ), ( 0x20D0, 0x20EF ), ( 0x302A, 0x302F ), + ( 0x3099, 0x309A ), ( 0xA806, 0xA806 ), ( 0xA80B, 0xA80B ), + ( 0xA825, 0xA826 ), ( 0xFB1E, 0xFB1E ), ( 0xFE00, 0xFE0F ), + ( 0xFE20, 0xFE23 ), ( 0xFEFF, 0xFEFF ), ( 0xFFF9, 0xFFFB ), + ( 0x10A01, 0x10A03 ), ( 0x10A05, 0x10A06 ), ( 0x10A0C, 0x10A0F ), + ( 0x10A38, 0x10A3A ), ( 0x10A3F, 0x10A3F ), ( 0x1D167, 0x1D169 ), + ( 0x1D173, 0x1D182 ), ( 0x1D185, 0x1D18B ), ( 0x1D1AA, 0x1D1AD ), + ( 0x1D242, 0x1D244 ), ( 0xE0001, 0xE0001 ), ( 0xE0020, 0xE007F ), + ( 0xE0100, 0xE01EF ) +] + +func width*(r: Rune): int = + let ucs = int(r) + # sorted list of non-overlapping intervals of non-spacing characters + # generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" + + # binary search in table of non-spacing characters + if bisearch(r, combining): + return 0 + + if r.isControlChar(): + return 2 + + # if we arrive here, ucs is not a combining or C0/C1 control character + + if (ucs >= 0x1100 and + (ucs <= 0x115f or # Hangul Jamo init. consonants + ucs == 0x2329 or ucs == 0x232a or + (ucs >= 0x2e80 and ucs <= 0xa4cf and + ucs != 0x303f) or # CJK ... Yi + (ucs >= 0xac00 and ucs <= 0xd7a3) or # Hangul Syllables + (ucs >= 0xf900 and ucs <= 0xfaff) or # CJK Compatibility Ideographs + (ucs >= 0xfe10 and ucs <= 0xfe19) or # Vertical forms + (ucs >= 0xfe30 and ucs <= 0xfe6f) or # CJK Compatibility Forms + (ucs >= 0xff00 and ucs <= 0xff60) or # Fullwidth Forms + (ucs >= 0xffe0 and ucs <= 0xffe6) or + (ucs >= 0x20000 and ucs <= 0x2fffd) or + (ucs >= 0x30000 and ucs <= 0x3fffd))): + return 2 + return 1 + +func width*(s: string): int = + for r in s.runes(): + result += width(r) + +func width*(s: seq[Rune]): int = + for r in s: + result += width(r) + +# +# The following functions are the same as mk_wcwidth() and +# mk_wcswidth(), except that spacing characters in the East Asian +# Ambiguous (A) category as defined in Unicode Technical Report #11 +# have a column width of 2. This variant might be useful for users of +# CJK legacy encodings who want to migrate to UCS without changing +# the traditional terminal character-width behaviour. It is not +# otherwise recommended for general use. +# +const ambiguous = [ + ( 0x00A1, 0x00A1 ), ( 0x00A4, 0x00A4 ), ( 0x00A7, 0x00A8 ), + ( 0x00AA, 0x00AA ), ( 0x00AE, 0x00AE ), ( 0x00B0, 0x00B4 ), + ( 0x00B6, 0x00BA ), ( 0x00BC, 0x00BF ), ( 0x00C6, 0x00C6 ), + ( 0x00D0, 0x00D0 ), ( 0x00D7, 0x00D8 ), ( 0x00DE, 0x00E1 ), + ( 0x00E6, 0x00E6 ), ( 0x00E8, 0x00EA ), ( 0x00EC, 0x00ED ), + ( 0x00F0, 0x00F0 ), ( 0x00F2, 0x00F3 ), ( 0x00F7, 0x00FA ), + ( 0x00FC, 0x00FC ), ( 0x00FE, 0x00FE ), ( 0x0101, 0x0101 ), + ( 0x0111, 0x0111 ), ( 0x0113, 0x0113 ), ( 0x011B, 0x011B ), + ( 0x0126, 0x0127 ), ( 0x012B, 0x012B ), ( 0x0131, 0x0133 ), + ( 0x0138, 0x0138 ), ( 0x013F, 0x0142 ), ( 0x0144, 0x0144 ), + ( 0x0148, 0x014B ), ( 0x014D, 0x014D ), ( 0x0152, 0x0153 ), + ( 0x0166, 0x0167 ), ( 0x016B, 0x016B ), ( 0x01CE, 0x01CE ), + ( 0x01D0, 0x01D0 ), ( 0x01D2, 0x01D2 ), ( 0x01D4, 0x01D4 ), + ( 0x01D6, 0x01D6 ), ( 0x01D8, 0x01D8 ), ( 0x01DA, 0x01DA ), + ( 0x01DC, 0x01DC ), ( 0x0251, 0x0251 ), ( 0x0261, 0x0261 ), + ( 0x02C4, 0x02C4 ), ( 0x02C7, 0x02C7 ), ( 0x02C9, 0x02CB ), + ( 0x02CD, 0x02CD ), ( 0x02D0, 0x02D0 ), ( 0x02D8, 0x02DB ), + ( 0x02DD, 0x02DD ), ( 0x02DF, 0x02DF ), ( 0x0391, 0x03A1 ), + ( 0x03A3, 0x03A9 ), ( 0x03B1, 0x03C1 ), ( 0x03C3, 0x03C9 ), + ( 0x0401, 0x0401 ), ( 0x0410, 0x044F ), ( 0x0451, 0x0451 ), + ( 0x2010, 0x2010 ), ( 0x2013, 0x2016 ), ( 0x2018, 0x2019 ), + ( 0x201C, 0x201D ), ( 0x2020, 0x2022 ), ( 0x2024, 0x2027 ), + ( 0x2030, 0x2030 ), ( 0x2032, 0x2033 ), ( 0x2035, 0x2035 ), + ( 0x203B, 0x203B ), ( 0x203E, 0x203E ), ( 0x2074, 0x2074 ), + ( 0x207F, 0x207F ), ( 0x2081, 0x2084 ), ( 0x20AC, 0x20AC ), + ( 0x2103, 0x2103 ), ( 0x2105, 0x2105 ), ( 0x2109, 0x2109 ), + ( 0x2113, 0x2113 ), ( 0x2116, 0x2116 ), ( 0x2121, 0x2122 ), + ( 0x2126, 0x2126 ), ( 0x212B, 0x212B ), ( 0x2153, 0x2154 ), + ( 0x215B, 0x215E ), ( 0x2160, 0x216B ), ( 0x2170, 0x2179 ), + ( 0x2190, 0x2199 ), ( 0x21B8, 0x21B9 ), ( 0x21D2, 0x21D2 ), + ( 0x21D4, 0x21D4 ), ( 0x21E7, 0x21E7 ), ( 0x2200, 0x2200 ), + ( 0x2202, 0x2203 ), ( 0x2207, 0x2208 ), ( 0x220B, 0x220B ), + ( 0x220F, 0x220F ), ( 0x2211, 0x2211 ), ( 0x2215, 0x2215 ), + ( 0x221A, 0x221A ), ( 0x221D, 0x2220 ), ( 0x2223, 0x2223 ), + ( 0x2225, 0x2225 ), ( 0x2227, 0x222C ), ( 0x222E, 0x222E ), + ( 0x2234, 0x2237 ), ( 0x223C, 0x223D ), ( 0x2248, 0x2248 ), + ( 0x224C, 0x224C ), ( 0x2252, 0x2252 ), ( 0x2260, 0x2261 ), + ( 0x2264, 0x2267 ), ( 0x226A, 0x226B ), ( 0x226E, 0x226F ), + ( 0x2282, 0x2283 ), ( 0x2286, 0x2287 ), ( 0x2295, 0x2295 ), + ( 0x2299, 0x2299 ), ( 0x22A5, 0x22A5 ), ( 0x22BF, 0x22BF ), + ( 0x2312, 0x2312 ), ( 0x2460, 0x24E9 ), ( 0x24EB, 0x254B ), + ( 0x2550, 0x2573 ), ( 0x2580, 0x258F ), ( 0x2592, 0x2595 ), + ( 0x25A0, 0x25A1 ), ( 0x25A3, 0x25A9 ), ( 0x25B2, 0x25B3 ), + ( 0x25B6, 0x25B7 ), ( 0x25BC, 0x25BD ), ( 0x25C0, 0x25C1 ), + ( 0x25C6, 0x25C8 ), ( 0x25CB, 0x25CB ), ( 0x25CE, 0x25D1 ), + ( 0x25E2, 0x25E5 ), ( 0x25EF, 0x25EF ), ( 0x2605, 0x2606 ), + ( 0x2609, 0x2609 ), ( 0x260E, 0x260F ), ( 0x2614, 0x2615 ), + ( 0x261C, 0x261C ), ( 0x261E, 0x261E ), ( 0x2640, 0x2640 ), + ( 0x2642, 0x2642 ), ( 0x2660, 0x2661 ), ( 0x2663, 0x2665 ), + ( 0x2667, 0x266A ), ( 0x266C, 0x266D ), ( 0x266F, 0x266F ), + ( 0x273D, 0x273D ), ( 0x2776, 0x277F ), ( 0xE000, 0xF8FF ), + ( 0xFFFD, 0xFFFD ), ( 0xF0000, 0xFFFFD ), ( 0x100000, 0x10FFFD ) +] + +func mk_wcwidth_cjk(ucs: Rune): int = + # sorted list of non-overlapping intervals of East Asian Ambiguous + # characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" + + # binary search in table of non-spacing characters + if bisearch(ucs, ambiguous): + return 2; + + return width(ucs); + +func mk_wcswidth_cjk(s: string): int = + for r in s.runes: + result += mk_wcwidth_cjk(r) + return result + +func skipBlanks*(buf: string, at: int): int = + result = at + while result < buf.len and buf[result].isWhitespace(): + inc result + +iterator split*(s: seq[Rune], sep: Rune): seq[Rune] = + var i = 0 + var prev = 0 + while i < s.len: + if s[i] == sep: + yield s.substr(prev, i) + prev = i + inc i + + if prev < i: + yield s.substr(prev, i) diff --git a/style.nim b/style.nim deleted file mode 100644 index e69de29b..00000000 diff --git a/termattrs.nim b/termattrs.nim deleted file mode 100644 index d49800ae..00000000 --- a/termattrs.nim +++ /dev/null @@ -1,11 +0,0 @@ -import terminal - -type - TermAttributes* = object - termWidth*: int - termHeight*: int - -proc getTermAttributes*(): TermAttributes = - let attrs = TermAttributes(termWidth: terminalWidth(), - termHeight: terminalHeight()) - return attrs diff --git a/twtio.nim b/twtio.nim deleted file mode 100644 index db811f40..00000000 --- a/twtio.nim +++ /dev/null @@ -1,180 +0,0 @@ -import terminal -import tables -import unicode - -import twtstr -import config -import radixtree - -template print*(s: varargs[string, `$`]) = - for x in s: - stdout.write(x) - -template printesc*(s: string) = - for r in s.runes: - if r.isControlChar(): - stdout.write(('^' & $($r)[0].getControlLetter()) - .ansiFgColor(fgBlue).ansiStyle(styleBright).ansiReset()) - else: - stdout.write($r) - -template eprint*(s: varargs[string, `$`]) = {.cast(noSideEffect).}: - var a = false - for x in s: - if not a: - a = true - else: - stderr.write(' ') - stderr.write(x) - stderr.write('\n') - -proc termGoto*(x: int, y: int) = - setCursorPos(stdout, x, y) - -proc getNormalAction*(s: string): TwtAction = - if normalActionRemap.hasKey(s): - return normalActionRemap[s] - return NO_ACTION - -proc getLinedAction*(s: string): TwtAction = - if linedActionRemap.hasKey(s): - return linedActionRemap[s] - return NO_ACTION - -proc readLine*(prompt: string, current: var string, termwidth: int): bool = - var news = current.toRunes() - let maxlen = termwidth - prompt.len - var s = "" - var feedNext = false - var escNext = false - var comp = false - var compi: uint16 = 0 - var compa = 0 - var comps = "" - var cursor = news.len - var shift = 0 - while true: - let rl = news.len - if cursor < shift: - shift = max(cursor - 1, 0) - else: - while news.substr(shift, shift + cursor).width() > maxlen - 1: - shift += news[^1].width() - - eraseLine() - printesc(prompt & $news.substr(shift, shift + maxlen - 1)) - - print('\r') - cursorForward(prompt.len + news.substr(shift, cursor).width()) - - if not feedNext: - s = "" - else: - feedNext = false - let c = getch() - s &= c - var action = getLinedAction(s) - if escNext: - action = NO_ACTION - case action - of ACTION_LINED_CANCEL: - return false - of ACTION_LINED_SUBMIT: - current = $news - return true - of ACTION_LINED_BACKSPACE: - if cursor > 0: - news = news.substr(0, cursor - 1) & news.substr(cursor) - dec cursor - of ACTION_LINED_DELETE: - if cursor > 0 and cursor < rl: - news = news.substr(0, cursor) & news.substr(cursor + 1) - of ACTION_LINED_ESC: - escNext = true - of ACTION_LINED_CLEAR: - news = news.substr(cursor) - cursor = 0 - of ACTION_LINED_KILL: - news = news.substr(0, cursor) - of ACTION_LINED_BACK: - if cursor > 0: - dec cursor - of ACTION_LINED_FORWARD: - if cursor < rl: - inc cursor - of ACTION_LINED_PREV_WORD: - while cursor > 0: - dec cursor - if news[cursor].breaksWord(): - break - of ACTION_LINED_NEXT_WORD: - while cursor < rl: - inc cursor - if cursor < rl: - if news[cursor].breaksWord(): - break - of ACTION_LINED_KILL_WORD: - var chars = 0 - while cursor > chars: - inc chars - if news[cursor - chars].breaksWord(): - break - if chars > 0: - news = news.substr(0, cursor - chars) & news.substr(cursor) - cursor -= chars - of ACTION_LINED_COMPOSE_ON: - comp = true - compi = 0 - compa = 0 - comps = "" - of ACTION_LINED_COMPOSE_OFF: - comp = false - compi = 0 - compa = 0 - comps = "" - of ACTION_LINED_COMPOSE_TOGGLE: - comp = not comp - compi = 0 - compa = 0 - comps = "" - of ACTION_FEED_NEXT: - feedNext = true - elif comp: - comps &= c - let n = composeRemap.getPrefix(comps, compi) - if n != compi: - compi = n - compa += comps.len - comps = "" - if composeRemap.hasPrefix(comps, compi) and composeRemap.nodes[n].children.len > 0: - feedNext = true - else: - var cs = "" - if composeRemap.nodes[compi].leaf: - cs = composeRemap.nodes[compi].value - else: - cs = s.substr(0, compa - 1) - comps = s.substr(compa) - if not composeRemap.hasPrefix(comps, 0): - cs &= comps - comps = "" - - news = news.substr(0, cursor) & cs.toRunes() & news.substr(cursor) - cursor += cs.runeLen() - compi = 0 - compa = 0 - elif validateUtf8(s) == -1: - var cs = "" - for c in s: - if not c.isControlChar(): - cs &= c - elif escNext: - cs &= c - escNext = false - escNext = false - if cs.len == 0: - continue - news = news.substr(0, cursor) & cs.toRunes() & news.substr(cursor) - cursor += cs.runeLen() - else: - feedNext = true diff --git a/twtstr.nim b/twtstr.nim deleted file mode 100644 index 42a64333..00000000 --- a/twtstr.nim +++ /dev/null @@ -1,352 +0,0 @@ -import terminal -import strutils -import unicode - -func ansiStyle*(str: string, style: Style): seq[string] = - result &= ansiStyleCode(style) - result &= str - -func ansiFgColor*(str: string, color: ForegroundColor): seq[string] = - result &= ansiForegroundColorCode(color) - result &= str - -func ansiReset*(str: string): seq[string] = - result &= str - result &= ansiResetCode - -func ansiStyle*(str: seq[string], style: Style): seq[string] = - return ansiStyleCode(style) & str - -func ansiFgColor*(str: seq[string], color: ForegroundColor): seq[string] = - return ansiForegroundColorCode(color) & str - -func ansiReset*(str: seq[string]): seq[string] = - return str & ansiResetCode - -func maxString*(str: string, max: int): string = - if max < str.runeLen(): - return str.runeSubstr(0, max - 2) & "$" - return str - -func fitValueToSize*(str: string, size: int): string = - if str.runeLen < size: - return str & ' '.repeat(size - str.runeLen) - return str.maxString(size) - -func buttonFmt*(str: string): seq[string] = - return "[".ansiFgColor(fgRed) & str.ansiFgColor(fgRed).ansiReset() & "]".ansiFgColor(fgRed).ansiReset() - -func buttonFmt*(str: seq[string]): seq[string] = - return "[".ansiFgColor(fgRed) & str.ansiFgColor(fgRed).ansiReset() & "]".ansiFgColor(fgRed).ansiReset() - -func buttonRaw*(str: string): string = - return "[" & str & "]" - -func remove*(str: string, c: string): string = - let rem = c.toRunes()[0] - for rune in str.runes: - if rem != rune: - result &= $rune - -const ControlChars = {chr(0x00)..chr(0x1F), chr(0x7F)} - -const Whitespace = { ' ', '\n', '\r', '\t' } - -func isWhitespace*(c: char): bool = - return c in Whitespace - -func isControlChar*(c: char): bool = - return c in ControlChars - -func isControlChar*(r: Rune): bool = - return int(r) <= int(high(char)) and char(r) in ControlChars - -func getControlChar*(c: char): char = - if c >= 'a': - return char(int(c) - int('a') + 1) - elif c == '?': - return char(127) - assert(false) - -func getControlLetter*(c: char): char = - if int(c) <= 0x1F: - return char(int(c) + int('A') - 1) - elif c == '\x7F': - return '?' - assert(false) - -func findChar*(str: string, c: char, start: int = 0): int = - var i = start - while i < str.len: - if str[i] == c: - return i - inc i - return -1 - -func findChar*(str: string, c: Rune, start: int = 0): int = - var i = start - var n = i - while i < str.runeLen(): - var r: Rune - fastRuneAt(str, n, r) - if r == c: - return i - i = n - return -1 - -func getLowerChars*(): string = - result = "" - for i in 0..255: - if chr(i) >= 'A' and chr(i) <= 'Z': - result &= chr(i + 32) - else: - result &= chr(i) - -const lowerChars = getLowerChars() - -func tolower*(c: char): char = - return lowerChars[int(c)] - -const breakWord = [ - Rune('\n'), Rune('/'), Rune('\\'), Rune(' '), Rune('&'), Rune('='), - Rune('?'), Rune('.'), Rune(';') -] - -func breaksWord*(r: Rune): bool = - return r in breakWord - -func substr*(s: seq[Rune], i: int, j: int): seq[Rune] = - if s.len == 0: - return @[] - return s[min(high(s), i)..min(high(s), j - 1)] - -func substr*(s: seq[Rune], i: int): seq[Rune] = - if i >= high(s) or s.len == 0: - return @[] - return s[min(high(s), i)..high(s)] - -#Measure length of rune. From https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - -#auxiliary function for binary search in interval table -func bisearch(ucs: Rune, table: openarray[(int, int)]): bool = - var max = table.high - var min = 0 - var mid: int - - if int(ucs) < table[0][0] or int(ucs) > table[max][1]: - return false - - while max >= min: - mid = (min + max) div 2 - if int(ucs) > table[mid][1]: - min = mid + 1 - elif int(ucs) < table[mid][0]: - max = mid - 1 - else: - return true - return false - -#The following two functions define the column width of an ISO 10646 -#character as follows: -# -# - The null character (U+0000) has a column width of 0. -# -# - Other C0/C1 control characters and DEL will lead to a return -# value of 2. -# -# - Non-spacing and enclosing combining characters (general -# category code Mn or Me in the Unicode database) have a -# column width of 0. -# -# - SOFT HYPHEN (U+00AD) has a column width of 1. -# -# - Other format characters (general category code Cf in the Unicode -# database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. -# -# - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) -# have a column width of 0. -# -# - Spacing characters in the East Asian Wide (W) or East Asian -# Full-width (F) category as defined in Unicode Technical -# Report #11 have a column width of 2. -# -# - All remaining characters (including all printable -# ISO 8859-1 and WGL4 characters, Unicode control characters, -# etc.) have a column width of 1. -# -#This implementation assumes that wchar_t characters are encoded -#in ISO 10646. -# - -const combining = [ - ( 0x0300, 0x036F ), ( 0x0483, 0x0486 ), ( 0x0488, 0x0489 ), - ( 0x0591, 0x05BD ), ( 0x05BF, 0x05BF ), ( 0x05C1, 0x05C2 ), - ( 0x05C4, 0x05C5 ), ( 0x05C7, 0x05C7 ), ( 0x0600, 0x0603 ), - ( 0x0610, 0x0615 ), ( 0x064B, 0x065E ), ( 0x0670, 0x0670 ), - ( 0x06D6, 0x06E4 ), ( 0x06E7, 0x06E8 ), ( 0x06EA, 0x06ED ), - ( 0x070F, 0x070F ), ( 0x0711, 0x0711 ), ( 0x0730, 0x074A ), - ( 0x07A6, 0x07B0 ), ( 0x07EB, 0x07F3 ), ( 0x0901, 0x0902 ), - ( 0x093C, 0x093C ), ( 0x0941, 0x0948 ), ( 0x094D, 0x094D ), - ( 0x0951, 0x0954 ), ( 0x0962, 0x0963 ), ( 0x0981, 0x0981 ), - ( 0x09BC, 0x09BC ), ( 0x09C1, 0x09C4 ), ( 0x09CD, 0x09CD ), - ( 0x09E2, 0x09E3 ), ( 0x0A01, 0x0A02 ), ( 0x0A3C, 0x0A3C ), - ( 0x0A41, 0x0A42 ), ( 0x0A47, 0x0A48 ), ( 0x0A4B, 0x0A4D ), - ( 0x0A70, 0x0A71 ), ( 0x0A81, 0x0A82 ), ( 0x0ABC, 0x0ABC ), - ( 0x0AC1, 0x0AC5 ), ( 0x0AC7, 0x0AC8 ), ( 0x0ACD, 0x0ACD ), - ( 0x0AE2, 0x0AE3 ), ( 0x0B01, 0x0B01 ), ( 0x0B3C, 0x0B3C ), - ( 0x0B3F, 0x0B3F ), ( 0x0B41, 0x0B43 ), ( 0x0B4D, 0x0B4D ), - ( 0x0B56, 0x0B56 ), ( 0x0B82, 0x0B82 ), ( 0x0BC0, 0x0BC0 ), - ( 0x0BCD, 0x0BCD ), ( 0x0C3E, 0x0C40 ), ( 0x0C46, 0x0C48 ), - ( 0x0C4A, 0x0C4D ), ( 0x0C55, 0x0C56 ), ( 0x0CBC, 0x0CBC ), - ( 0x0CBF, 0x0CBF ), ( 0x0CC6, 0x0CC6 ), ( 0x0CCC, 0x0CCD ), - ( 0x0CE2, 0x0CE3 ), ( 0x0D41, 0x0D43 ), ( 0x0D4D, 0x0D4D ), - ( 0x0DCA, 0x0DCA ), ( 0x0DD2, 0x0DD4 ), ( 0x0DD6, 0x0DD6 ), - ( 0x0E31, 0x0E31 ), ( 0x0E34, 0x0E3A ), ( 0x0E47, 0x0E4E ), - ( 0x0EB1, 0x0EB1 ), ( 0x0EB4, 0x0EB9 ), ( 0x0EBB, 0x0EBC ), - ( 0x0EC8, 0x0ECD ), ( 0x0F18, 0x0F19 ), ( 0x0F35, 0x0F35 ), - ( 0x0F37, 0x0F37 ), ( 0x0F39, 0x0F39 ), ( 0x0F71, 0x0F7E ), - ( 0x0F80, 0x0F84 ), ( 0x0F86, 0x0F87 ), ( 0x0F90, 0x0F97 ), - ( 0x0F99, 0x0FBC ), ( 0x0FC6, 0x0FC6 ), ( 0x102D, 0x1030 ), - ( 0x1032, 0x1032 ), ( 0x1036, 0x1037 ), ( 0x1039, 0x1039 ), - ( 0x1058, 0x1059 ), ( 0x1160, 0x11FF ), ( 0x135F, 0x135F ), - ( 0x1712, 0x1714 ), ( 0x1732, 0x1734 ), ( 0x1752, 0x1753 ), - ( 0x1772, 0x1773 ), ( 0x17B4, 0x17B5 ), ( 0x17B7, 0x17BD ), - ( 0x17C6, 0x17C6 ), ( 0x17C9, 0x17D3 ), ( 0x17DD, 0x17DD ), - ( 0x180B, 0x180D ), ( 0x18A9, 0x18A9 ), ( 0x1920, 0x1922 ), - ( 0x1927, 0x1928 ), ( 0x1932, 0x1932 ), ( 0x1939, 0x193B ), - ( 0x1A17, 0x1A18 ), ( 0x1B00, 0x1B03 ), ( 0x1B34, 0x1B34 ), - ( 0x1B36, 0x1B3A ), ( 0x1B3C, 0x1B3C ), ( 0x1B42, 0x1B42 ), - ( 0x1B6B, 0x1B73 ), ( 0x1DC0, 0x1DCA ), ( 0x1DFE, 0x1DFF ), - ( 0x200B, 0x200F ), ( 0x202A, 0x202E ), ( 0x2060, 0x2063 ), - ( 0x206A, 0x206F ), ( 0x20D0, 0x20EF ), ( 0x302A, 0x302F ), - ( 0x3099, 0x309A ), ( 0xA806, 0xA806 ), ( 0xA80B, 0xA80B ), - ( 0xA825, 0xA826 ), ( 0xFB1E, 0xFB1E ), ( 0xFE00, 0xFE0F ), - ( 0xFE20, 0xFE23 ), ( 0xFEFF, 0xFEFF ), ( 0xFFF9, 0xFFFB ), - ( 0x10A01, 0x10A03 ), ( 0x10A05, 0x10A06 ), ( 0x10A0C, 0x10A0F ), - ( 0x10A38, 0x10A3A ), ( 0x10A3F, 0x10A3F ), ( 0x1D167, 0x1D169 ), - ( 0x1D173, 0x1D182 ), ( 0x1D185, 0x1D18B ), ( 0x1D1AA, 0x1D1AD ), - ( 0x1D242, 0x1D244 ), ( 0xE0001, 0xE0001 ), ( 0xE0020, 0xE007F ), - ( 0xE0100, 0xE01EF ) -] - -func width*(r: Rune): int = - let ucs = int(r) - # sorted list of non-overlapping intervals of non-spacing characters - # generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" - - # binary search in table of non-spacing characters - if bisearch(r, combining): - return 0 - - if r.isControlChar(): - return 2 - - # if we arrive here, ucs is not a combining or C0/C1 control character - - if (ucs >= 0x1100 and - (ucs <= 0x115f or # Hangul Jamo init. consonants - ucs == 0x2329 or ucs == 0x232a or - (ucs >= 0x2e80 and ucs <= 0xa4cf and - ucs != 0x303f) or # CJK ... Yi - (ucs >= 0xac00 and ucs <= 0xd7a3) or # Hangul Syllables - (ucs >= 0xf900 and ucs <= 0xfaff) or # CJK Compatibility Ideographs - (ucs >= 0xfe10 and ucs <= 0xfe19) or # Vertical forms - (ucs >= 0xfe30 and ucs <= 0xfe6f) or # CJK Compatibility Forms - (ucs >= 0xff00 and ucs <= 0xff60) or # Fullwidth Forms - (ucs >= 0xffe0 and ucs <= 0xffe6) or - (ucs >= 0x20000 and ucs <= 0x2fffd) or - (ucs >= 0x30000 and ucs <= 0x3fffd))): - return 2 - return 1 - -func width*(s: string): int = - for r in s.runes(): - result += width(r) - -func width*(s: seq[Rune]): int = - for r in s: - result += width(r) - -# -# The following functions are the same as mk_wcwidth() and -# mk_wcswidth(), except that spacing characters in the East Asian -# Ambiguous (A) category as defined in Unicode Technical Report #11 -# have a column width of 2. This variant might be useful for users of -# CJK legacy encodings who want to migrate to UCS without changing -# the traditional terminal character-width behaviour. It is not -# otherwise recommended for general use. -# -const ambiguous = [ - ( 0x00A1, 0x00A1 ), ( 0x00A4, 0x00A4 ), ( 0x00A7, 0x00A8 ), - ( 0x00AA, 0x00AA ), ( 0x00AE, 0x00AE ), ( 0x00B0, 0x00B4 ), - ( 0x00B6, 0x00BA ), ( 0x00BC, 0x00BF ), ( 0x00C6, 0x00C6 ), - ( 0x00D0, 0x00D0 ), ( 0x00D7, 0x00D8 ), ( 0x00DE, 0x00E1 ), - ( 0x00E6, 0x00E6 ), ( 0x00E8, 0x00EA ), ( 0x00EC, 0x00ED ), - ( 0x00F0, 0x00F0 ), ( 0x00F2, 0x00F3 ), ( 0x00F7, 0x00FA ), - ( 0x00FC, 0x00FC ), ( 0x00FE, 0x00FE ), ( 0x0101, 0x0101 ), - ( 0x0111, 0x0111 ), ( 0x0113, 0x0113 ), ( 0x011B, 0x011B ), - ( 0x0126, 0x0127 ), ( 0x012B, 0x012B ), ( 0x0131, 0x0133 ), - ( 0x0138, 0x0138 ), ( 0x013F, 0x0142 ), ( 0x0144, 0x0144 ), - ( 0x0148, 0x014B ), ( 0x014D, 0x014D ), ( 0x0152, 0x0153 ), - ( 0x0166, 0x0167 ), ( 0x016B, 0x016B ), ( 0x01CE, 0x01CE ), - ( 0x01D0, 0x01D0 ), ( 0x01D2, 0x01D2 ), ( 0x01D4, 0x01D4 ), - ( 0x01D6, 0x01D6 ), ( 0x01D8, 0x01D8 ), ( 0x01DA, 0x01DA ), - ( 0x01DC, 0x01DC ), ( 0x0251, 0x0251 ), ( 0x0261, 0x0261 ), - ( 0x02C4, 0x02C4 ), ( 0x02C7, 0x02C7 ), ( 0x02C9, 0x02CB ), - ( 0x02CD, 0x02CD ), ( 0x02D0, 0x02D0 ), ( 0x02D8, 0x02DB ), - ( 0x02DD, 0x02DD ), ( 0x02DF, 0x02DF ), ( 0x0391, 0x03A1 ), - ( 0x03A3, 0x03A9 ), ( 0x03B1, 0x03C1 ), ( 0x03C3, 0x03C9 ), - ( 0x0401, 0x0401 ), ( 0x0410, 0x044F ), ( 0x0451, 0x0451 ), - ( 0x2010, 0x2010 ), ( 0x2013, 0x2016 ), ( 0x2018, 0x2019 ), - ( 0x201C, 0x201D ), ( 0x2020, 0x2022 ), ( 0x2024, 0x2027 ), - ( 0x2030, 0x2030 ), ( 0x2032, 0x2033 ), ( 0x2035, 0x2035 ), - ( 0x203B, 0x203B ), ( 0x203E, 0x203E ), ( 0x2074, 0x2074 ), - ( 0x207F, 0x207F ), ( 0x2081, 0x2084 ), ( 0x20AC, 0x20AC ), - ( 0x2103, 0x2103 ), ( 0x2105, 0x2105 ), ( 0x2109, 0x2109 ), - ( 0x2113, 0x2113 ), ( 0x2116, 0x2116 ), ( 0x2121, 0x2122 ), - ( 0x2126, 0x2126 ), ( 0x212B, 0x212B ), ( 0x2153, 0x2154 ), - ( 0x215B, 0x215E ), ( 0x2160, 0x216B ), ( 0x2170, 0x2179 ), - ( 0x2190, 0x2199 ), ( 0x21B8, 0x21B9 ), ( 0x21D2, 0x21D2 ), - ( 0x21D4, 0x21D4 ), ( 0x21E7, 0x21E7 ), ( 0x2200, 0x2200 ), - ( 0x2202, 0x2203 ), ( 0x2207, 0x2208 ), ( 0x220B, 0x220B ), - ( 0x220F, 0x220F ), ( 0x2211, 0x2211 ), ( 0x2215, 0x2215 ), - ( 0x221A, 0x221A ), ( 0x221D, 0x2220 ), ( 0x2223, 0x2223 ), - ( 0x2225, 0x2225 ), ( 0x2227, 0x222C ), ( 0x222E, 0x222E ), - ( 0x2234, 0x2237 ), ( 0x223C, 0x223D ), ( 0x2248, 0x2248 ), - ( 0x224C, 0x224C ), ( 0x2252, 0x2252 ), ( 0x2260, 0x2261 ), - ( 0x2264, 0x2267 ), ( 0x226A, 0x226B ), ( 0x226E, 0x226F ), - ( 0x2282, 0x2283 ), ( 0x2286, 0x2287 ), ( 0x2295, 0x2295 ), - ( 0x2299, 0x2299 ), ( 0x22A5, 0x22A5 ), ( 0x22BF, 0x22BF ), - ( 0x2312, 0x2312 ), ( 0x2460, 0x24E9 ), ( 0x24EB, 0x254B ), - ( 0x2550, 0x2573 ), ( 0x2580, 0x258F ), ( 0x2592, 0x2595 ), - ( 0x25A0, 0x25A1 ), ( 0x25A3, 0x25A9 ), ( 0x25B2, 0x25B3 ), - ( 0x25B6, 0x25B7 ), ( 0x25BC, 0x25BD ), ( 0x25C0, 0x25C1 ), - ( 0x25C6, 0x25C8 ), ( 0x25CB, 0x25CB ), ( 0x25CE, 0x25D1 ), - ( 0x25E2, 0x25E5 ), ( 0x25EF, 0x25EF ), ( 0x2605, 0x2606 ), - ( 0x2609, 0x2609 ), ( 0x260E, 0x260F ), ( 0x2614, 0x2615 ), - ( 0x261C, 0x261C ), ( 0x261E, 0x261E ), ( 0x2640, 0x2640 ), - ( 0x2642, 0x2642 ), ( 0x2660, 0x2661 ), ( 0x2663, 0x2665 ), - ( 0x2667, 0x266A ), ( 0x266C, 0x266D ), ( 0x266F, 0x266F ), - ( 0x273D, 0x273D ), ( 0x2776, 0x277F ), ( 0xE000, 0xF8FF ), - ( 0xFFFD, 0xFFFD ), ( 0xF0000, 0xFFFFD ), ( 0x100000, 0x10FFFD ) -] - -func mk_wcwidth_cjk(ucs: Rune): int = - # sorted list of non-overlapping intervals of East Asian Ambiguous - # characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" - - # binary search in table of non-spacing characters - if bisearch(ucs, ambiguous): - return 2; - - return width(ucs); - -func mk_wcswidth_cjk(s: string): int = - for r in s.runes: - result += mk_wcwidth_cjk(r) - return result - - -proc skipBlanks*(buf: string, at: var int) = - while at < buf.len and buf[at].isWhitespace(): - inc at -- cgit 1.4.1-2-gfad0