├── .travis.yml ├── .gitignore ├── src └── html │ ├── package.d │ ├── utils.d │ ├── parser.d │ ├── entities.d │ └── dom.d ├── .editorconfig ├── dub.json ├── LICENSE ├── scripts └── genentities.d └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: d 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | *.o 5 | *.obj 6 | *.a 7 | *.lib 8 | -------------------------------------------------------------------------------- /src/html/package.d: -------------------------------------------------------------------------------- 1 | module html; 2 | 3 | 4 | public import html.dom; 5 | public import html.entities; 6 | public import html.parser; 7 | 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{c,h,d,di,dd,json}] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = tab 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | charset = utf-8 10 | -------------------------------------------------------------------------------- /dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "htmld", 3 | "description": "Lightweight and forgiving HTML parser", 4 | "copyright": "Copyright © 2015, Marcio Martins", 5 | "authors": [ "Márcio Martins" ], 6 | "license": "MIT License", 7 | "targetType": "library", 8 | "targetName": "htmld", 9 | "dependencies": { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 eBookingServices 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /scripts/genentities.d: -------------------------------------------------------------------------------- 1 | import std.algorithm; 2 | import std.array; 3 | import std.bitmanip; 4 | import std.conv; 5 | import std.file; 6 | import std.json; 7 | import std.stdio; 8 | import std.utf; 9 | 10 | 11 | void main() { 12 | auto text = readText("entities.json"); 13 | auto json = parseJSON(text); 14 | assert(json.type == JSON_TYPE.OBJECT); 15 | 16 | ubyte[] codes; 17 | uint[string] offsets; 18 | 19 | auto dchars = uninitializedArray!(dchar[])(32); 20 | auto minlen = int.max; 21 | auto maxlen = int.min; 22 | foreach(string key, value; json) { 23 | assert(value.type == JSON_TYPE.OBJECT); 24 | auto codepoints = value["codepoints"]; 25 | 26 | dchars.length = codepoints.array.length; 27 | foreach(uint i, dcharjson; codepoints) 28 | dchars[i] = cast(dchar)dcharjson.integer; 29 | 30 | uint offset = codes.length; 31 | 32 | auto code = cast(ubyte[])toUTF8(dchars); 33 | auto found = codes.find(code); 34 | if (found.length) { 35 | offset = codes.length - found.length; 36 | } else { 37 | codes ~= cast(ubyte[])toUTF8(dchars); 38 | } 39 | uint length = code.length; 40 | 41 | assert(offset < (1 << 28)); 42 | assert(length < (1 << 4)); 43 | offset = (offset << 4) | length; 44 | 45 | if (key.front == '&') 46 | key = key[1..$]; 47 | if (key.back == ';') 48 | key = key[0..$-1]; 49 | 50 | offsets[key] = offset; 51 | minlen = min(key.length, minlen); 52 | maxlen = max(key.length, maxlen); 53 | } 54 | 55 | auto output = appender!(const(char)[]); 56 | 57 | output.put("__gshared immutable static ubyte["); 58 | output.put(codes.length.to!string); 59 | output.put("] bytes_ = "); 60 | output.put(codes.to!string.replace(", ", ",")); 61 | output.put(";\n"); 62 | output.put("__gshared immutable static uint[const(char)[]] index_ = "); 63 | output.put(offsets.to!string.replace(", ", ",")); 64 | output.put(";\n"); 65 | output.put("enum MinEntityNameLength = "); 66 | output.put(minlen.to!string); 67 | output.put(";\n"); 68 | output.put("enum MaxEntityNameLength = "); 69 | output.put(maxlen.to!string); 70 | output.put(";\n"); 71 | 72 | std.file.write("entities.d.mixin", output.data); 73 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # htmld [](https://travis-ci.org/eBookingServices/htmld) 2 | Lightweight and forgiving HTML parser and DOM. 3 | 4 | The parser was inspired by [htmlparse2](https://github.com/fb55/htmlparser2) by [fb55](https://github.com/fb55) 5 | 6 | HTML Entity parsing and decoding are both optional. The current parser interface is based on callbacks. 7 | It can also output compact HTML, and can do basic validation. 8 | 9 | 10 | Creating the DOM from source: 11 | ```d 12 | auto doc = createDocument(`
`); 13 | writeln(doc.root.outerHTML); 14 | ``` 15 | 16 | 17 | Creating/mutating DOM manually: 18 | ```d 19 | auto doc = createDocument(); 20 | doc.root.html = ` `; 21 | 22 | auto container = doc.createElement("div", doc.root.firstChild); 23 | container.attr("class", "container"); 24 | container.html = "moo!
"; 25 | 26 | auto app = appender!string; 27 | doc.root.outerHTML(app); 28 | ``` 29 | 30 | 31 | Compacting HTML: 32 | ```d 33 | auto doc = createDocument!(DOMCreateOptions.none)("\n abc \n"); 34 | writeln(doc.root.compactHTML); 35 | ``` 36 | 37 | 38 | QuerySelector interface: 39 | ```d 40 | if (auto p = doc.querySelector("p:nth-of-type(2)")) 41 | p.text = "mooo"; 42 | 43 | foreach(p; doc.querySelectorAll("p")) { 44 | p.text = "mooo"; 45 | } 46 | ``` 47 | 48 | 49 | Example parser usage: 50 | ```d 51 | auto builder = DOMBuilder(); 52 | parseHTML(` `, builder); 53 | ``` 54 | 55 | 56 | Example handler: 57 | ```d 58 | struct DOMBuilder { 59 | void onText(const(char)[] data) {} 60 | void onSelfClosing() {} 61 | void onOpenStart(const(char)[] data) {} 62 | void onOpenEnd(const(char)[] data) {} 63 | void onClose(const(char)[] data) {} 64 | void onAttrName(const(char)[] data) {} 65 | void onAttrEnd() {} 66 | void onAttrValue(const(char)[] data) {} 67 | void onComment(const(char)[] data) {} 68 | void onDeclaration(const(char)[] data) {} 69 | void onProcessingInstruction(const(char)[] data) {} 70 | void onCDATA(const(char)[] data) {} 71 | 72 | // the following are required if ParseEntities is set 73 | void onNamedEntity(const(char)[] data) {} 74 | void onNumericEntity(const(char)[] data) {} 75 | void onHexEntity(const(char)[] data) {} 76 | 77 | // required only if DecodeEntities is set 78 | void onEntity(const(char)[] data, const(char)[] decoded) {} 79 | 80 | void onDocumentEnd() {} 81 | } 82 | ``` 83 | 84 | 85 | # todo 86 | - implement range-based interface for parser 87 | - implement a basic validation mode 88 | -------------------------------------------------------------------------------- /src/html/utils.d: -------------------------------------------------------------------------------- 1 | module html.utils; 2 | 3 | 4 | import std.ascii; 5 | import std.typecons; 6 | 7 | 8 | bool isAllWhite(Char)(Char[] value) { 9 | auto ptr = value.ptr; 10 | const end = ptr + value.length; 11 | 12 | while (ptr != end) { 13 | if (!isWhite(*ptr++)) 14 | return false; 15 | } 16 | return true; 17 | } 18 | 19 | 20 | bool requiresQuotes(Char)(Char[] value) { 21 | auto ptr = value.ptr; 22 | const end = ptr + value.length; 23 | 24 | while (ptr != end) { 25 | switch (*ptr++) { 26 | case 'a': .. case 'z': 27 | case 'A': .. case 'Z': 28 | case '0': .. case '9': 29 | case '-': 30 | case '_': 31 | case '.': 32 | case ':': 33 | continue; 34 | default: 35 | return true; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | 42 | bool equalsCI(CharA, CharB)(const(CharA)[] a, const(CharB)[] b) { 43 | if (a.length == b.length) { 44 | for (size_t i; i < a.length; ++i) { 45 | if (std.ascii.toLower(a.ptr[i]) != std.ascii.toLower(b.ptr[i])) 46 | return false; 47 | } 48 | return true; 49 | } 50 | return false; 51 | } 52 | 53 | 54 | enum QuickHash64Seed = 14695981039346656037u; 55 | enum QuickHash64Scale = 1099511628211u; 56 | 57 | 58 | ulong quickHash64(const(char)* p, const(char)* pend, ulong hash = QuickHash64Seed) { 59 | while (p != pend) 60 | hash = (hash ^ cast(ulong)(*p++)) * QuickHash64Scale; 61 | return hash; 62 | } 63 | 64 | 65 | ulong quickHash64i(const(char)* p, const(char)* pend, ulong hash = QuickHash64Seed) { 66 | while (p != pend) 67 | hash = (hash ^ cast(ulong)(std.ascii.toLower(*p++))) * QuickHash64Scale; 68 | return hash; 69 | } 70 | 71 | 72 | hash_t quickHashOf(const(char)[] x) { 73 | return cast(hash_t)quickHash64(x.ptr, x.ptr + x.length); 74 | } 75 | 76 | 77 | hash_t tagHashOf(const(char)[] x) { 78 | return cast(hash_t)quickHash64i(x.ptr, x.ptr + x.length); 79 | } 80 | 81 | 82 | void writeQuotesEscaped(Appender)(ref Appender app, const(char)[] x) { 83 | auto ptr = x.ptr; 84 | const end = x.ptr + x.length; 85 | 86 | while (ptr != end) { 87 | const ch = *ptr++; 88 | if (ch != '"') { 89 | app.put(ch); 90 | } else { 91 | app.put("""); // shorter than " 92 | } 93 | } 94 | } 95 | 96 | 97 | void writeHTMLEscaped(Flag!q{escapeQuotes} escapeQuotes, Appender)(ref Appender app, const(char)[] x) { 98 | auto ptr = x.ptr; 99 | const end = x.ptr + x.length; 100 | 101 | while (ptr != end) { 102 | const ch = *ptr++; 103 | switch (ch) { 104 | static if (escapeQuotes) { 105 | case '"': 106 | app.put("""); // shorter than " 107 | break; 108 | } 109 | case '<': 110 | app.put("<"); 111 | break; 112 | case '>': 113 | app.put(">"); 114 | break; 115 | case '&': 116 | app.put("&"); 117 | break; 118 | default: 119 | app.put(ch); 120 | break; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/html/parser.d: -------------------------------------------------------------------------------- 1 | module html.parser; 2 | 3 | 4 | import std.algorithm; 5 | import std.array; 6 | import std.ascii; 7 | import std.conv; 8 | import std.traits; 9 | 10 | import html.entities; 11 | import html.utils; 12 | 13 | 14 | private enum ParserStates { 15 | Text = 1, 16 | 17 | // tags 18 | PreTagName, 19 | TagName, 20 | SelfClosingTag, 21 | PreClosingTagName, 22 | ClosingTagName, 23 | PostClosingTagName, 24 | 25 | //attributes 26 | PreAttrName, 27 | AttrName, 28 | PostAttrName, 29 | PreAttrValue, 30 | AttrValueDQ, 31 | AttrValueSQ, 32 | AttrValueNQ, 33 | 34 | // decls 35 | PreDeclaration, 36 | Declaration, 37 | ProcessingInstruction, 38 | PreComment, 39 | Comment, 40 | PostComment1, 41 | PostComment2, 42 | 43 | // entities 44 | PreEntity, 45 | PreNumericEntity, 46 | NamedEntity, 47 | NumericEntity, 48 | HexEntity, 49 | 50 | // cdata 51 | PreCDATA, 52 | PreCDATA_C, 53 | PreCDATA_CD, 54 | PreCDATA_CDA, 55 | PreCDATA_CDAT, 56 | PreCDATA_CDATA, 57 | CDATA, 58 | PostCDATA1, 59 | PostCDATA2, 60 | 61 | // scripts / style 62 | PreScriptOrStyle, 63 | PreScript_SC, 64 | PreScript_SCR, 65 | PreScript_SCRI, 66 | PreScript_SCRIP, 67 | PreScript_SCRIPT, 68 | PreStyle_ST, 69 | PreStyle_STY, 70 | PreStyle_STYL, 71 | PreStyle_STYLE, 72 | PreClosingScriptOrStyle, 73 | ClosingScript_SC, 74 | ClosingScript_SCR, 75 | ClosingScript_SCRI, 76 | ClosingScript_SCRIP, 77 | ClosingScript_SCRIPT, 78 | ClosingStyle_ST, 79 | ClosingStyle_STY, 80 | ClosingStyle_STYL, 81 | ClosingStyle_STYLE, 82 | } 83 | 84 | 85 | private enum ParserTextStates { 86 | Normal = 0, 87 | Script, 88 | Style, 89 | } 90 | 91 | 92 | enum ParserOptions { 93 | ParseEntities = 1 << 0, 94 | DecodeEntities = 1 << 1, 95 | 96 | None = 0, 97 | Default = ParseEntities | DecodeEntities, 98 | } 99 | 100 | 101 | private auto parseNamedEntity(Handler, size_t options)(ref const(char)* start, ref const(char)* ptr, ref Handler handler) { 102 | auto length = ptr - start - 1; 103 | if (start[1+length-1] == ';') 104 | --length; 105 | 106 | if (!length) 107 | return false; 108 | 109 | auto limit = min(1+MaxLegacyEntityNameLength, length); 110 | auto name = start[1..1+length]; 111 | 112 | while (true) { 113 | if (auto pindex = name in index_) { 114 | handler.onNamedEntity(name); 115 | static if ((options & ParserOptions.DecodeEntities) != 0) { 116 | auto offset = codeOffset(*pindex); 117 | handler.onEntity(name, cast(const(char)[])bytes_[offset..offset + codeLength(*pindex)]); 118 | } 119 | 120 | start += 1 + name.length; 121 | return true; 122 | } else { 123 | if (limit <= MinEntityNameLength) 124 | return false; 125 | --limit; 126 | name = start[1..1+limit]; 127 | continue; 128 | } 129 | } 130 | } 131 | 132 | private auto parseNumericEntity(Handler, size_t options)(ref const(char)* start, ref const(char)* ptr, ref Handler handler) { 133 | auto length = (ptr - start) - 2; 134 | if (start[1+length-1] == ';') 135 | --length; 136 | 137 | if (!length) 138 | return false; 139 | auto name = start[2..2+length]; 140 | handler.onNumericEntity(name); 141 | 142 | static if ((options & ParserOptions.DecodeEntities) != 0) { 143 | auto cname = name[0..min(8, name.length)]; 144 | auto code = parse!uint(cname, 10); 145 | handler.onEntity(start[2..2+length], decodeCodePoint(code)); 146 | } 147 | 148 | start = ptr; 149 | return true; 150 | } 151 | 152 | private auto parseHexEntity(Handler, size_t options)(ref const(char)* start, ref const(char)* ptr, ref Handler handler) { 153 | auto length = (ptr - start) - 3; 154 | if (start[1+length-1] == ';') 155 | --length; 156 | 157 | if (!length) 158 | return false; 159 | 160 | auto name = start[3..3+length]; 161 | handler.onHexEntity(name); 162 | 163 | static if ((options & ParserOptions.DecodeEntities) != 0) { 164 | auto cname = name[0..min(6, name.length)]; 165 | auto code = parse!uint(cname, 16); 166 | handler.onEntity(name, decodeCodePoint(code)); 167 | } 168 | 169 | start = ptr; 170 | return true; 171 | } 172 | 173 | void parseHTML(Handler, size_t options = ParserOptions.Default)(const(char)[] source, ref Handler handler) { 174 | auto ptr = source.ptr; 175 | auto end = source.ptr + source.length; 176 | auto start = ptr; 177 | 178 | ParserStates state = ParserStates.Text; 179 | ParserStates saved = ParserStates.Text; 180 | ParserTextStates textState = ParserTextStates.Normal; 181 | 182 | enum ParseEntities = (options & (ParserOptions.ParseEntities | ParserOptions.DecodeEntities)) != 0; 183 | enum DecodeEntities = (options & ParserOptions.DecodeEntities) != 0; 184 | 185 | while (ptr != end) { 186 | final switch(state) with (ParserStates) { 187 | case Text: 188 | final switch (textState) with (ParserTextStates) { 189 | case Normal: 190 | static if (ParseEntities) { 191 | while ((ptr != end) && (*ptr != '<') && (*ptr != '&')) 192 | ++ptr; 193 | } else { 194 | while ((ptr != end) && (*ptr != '<')) 195 | ++ptr; 196 | } 197 | break; 198 | case Script: 199 | case Style: 200 | while ((ptr != end) && ((*ptr != '<') || (ptr + 1 == end) || (*(ptr + 1) != '/'))) 201 | ++ptr; 202 | } 203 | if (ptr == end) 204 | continue; 205 | 206 | static if (ParseEntities) { 207 | auto noEntity = *ptr != '&'; 208 | } else { 209 | enum noEntity = true; 210 | } 211 | 212 | if (noEntity) { 213 | if (start != ptr) 214 | handler.onText(start[0..ptr-start]); 215 | state = PreTagName; 216 | start = ptr; 217 | } else { 218 | static if (ParseEntities) { 219 | if (start != ptr) 220 | handler.onText(start[0..ptr-start]); 221 | saved = state; 222 | state = PreEntity; 223 | start = ptr; 224 | } 225 | } 226 | break; 227 | 228 | case PreTagName: 229 | if (*ptr == '/') { 230 | state = PreClosingTagName; 231 | } else if ((*ptr == '>') || isWhite(*ptr) || (textState != ParserTextStates.Normal)) { 232 | state = Text; 233 | } else { 234 | switch (*ptr) { 235 | case '!': 236 | state = PreDeclaration; 237 | start = ptr + 1; 238 | break; 239 | case '?': 240 | state = ProcessingInstruction; 241 | start = ptr + 1; 242 | break; 243 | case '<': 244 | handler.onText(start[0..ptr-start]); 245 | start = ptr + 1; 246 | break; 247 | default: 248 | if ((*ptr == 's') || (*ptr == 'S')) { 249 | state = PreScriptOrStyle; 250 | } else { 251 | state = TagName; 252 | } 253 | start = ptr; 254 | break; 255 | } 256 | } 257 | break; 258 | 259 | case PreScriptOrStyle: 260 | if ((*ptr == 'c') || (*ptr == 'C')) { 261 | state = PreScript_SC; 262 | } else if ((*ptr == 't') || (*ptr == 'T')) { 263 | state = PreStyle_ST; 264 | } else { 265 | state = TagName; 266 | goto case TagName; 267 | } 268 | break; 269 | 270 | case TagName: 271 | while ((ptr != end) && (*ptr != '/') && (*ptr != '>') && !isWhite(*ptr)) 272 | ++ptr; 273 | if (ptr == end) 274 | continue; 275 | 276 | handler.onOpenStart(start[0..ptr-start]); 277 | state = PreAttrName; 278 | continue; 279 | 280 | case PreClosingTagName: 281 | while ((ptr != end) && isWhite(*ptr)) 282 | ++ptr; 283 | if (ptr == end) 284 | continue; 285 | 286 | if (*ptr == '>') { 287 | state = Text; 288 | } else if (textState != ParserTextStates.Normal) { 289 | if ((*ptr == 's') || (*ptr == 'S')) { 290 | state = PreClosingScriptOrStyle; 291 | } else { 292 | state = Text; 293 | continue; 294 | } 295 | } else { 296 | state = ClosingTagName; 297 | start = ptr; 298 | } 299 | break; 300 | 301 | case PreClosingScriptOrStyle: 302 | if ((textState == ParserTextStates.Script) && ((*ptr == 'c') || (*ptr == 'C'))) { 303 | state = ClosingScript_SC; 304 | } else if ((textState == ParserTextStates.Style) && ((*ptr == 't') || (*ptr == 'T'))) { 305 | state = ClosingStyle_ST; 306 | } else { 307 | state = Text; 308 | goto case Text; 309 | } 310 | break; 311 | 312 | case ClosingTagName: 313 | while ((ptr != end) && (*ptr != '>') && !isWhite(*ptr)) 314 | ++ptr; 315 | if (ptr == end) 316 | continue; 317 | 318 | handler.onClose(start[0..ptr-start]); 319 | state = PostClosingTagName; 320 | continue; 321 | 322 | case PostClosingTagName: 323 | while ((ptr != end) && (*ptr != '>')) 324 | ++ptr; 325 | if (ptr == end) 326 | continue; 327 | 328 | state = Text; 329 | start = ptr + 1; 330 | break; 331 | 332 | case SelfClosingTag: 333 | while ((ptr != end) && (*ptr != '>') && isWhite(*ptr)) 334 | ++ptr; 335 | if (ptr == end) 336 | continue; 337 | 338 | if (*ptr == '>') { 339 | handler.onSelfClosing(); 340 | state = Text; 341 | start = ptr + 1; 342 | } else { 343 | state = PreAttrName; 344 | continue; 345 | } 346 | break; 347 | 348 | case PreAttrName: 349 | while ((ptr != end) && (*ptr != '>') && (*ptr != '/') && isWhite(*ptr)) 350 | ++ptr; 351 | if (ptr == end) 352 | continue; 353 | 354 | if (*ptr == '>') { 355 | handler.onOpenEnd(start[0..ptr-start]); 356 | state = Text; 357 | start = ptr + 1; 358 | } else if (*ptr == '/') { 359 | state = SelfClosingTag; 360 | } else { 361 | state = AttrName; 362 | start = ptr; 363 | } 364 | break; 365 | 366 | case AttrName: 367 | while ((ptr != end) && (*ptr != '=') && (*ptr != '>') && (*ptr != '/') && !isWhite(*ptr)) 368 | ++ptr; 369 | if (ptr == end) 370 | continue; 371 | 372 | handler.onAttrName(start[0..ptr-start]); 373 | state = PostAttrName; 374 | start = ptr; 375 | continue; 376 | 377 | case PostAttrName: 378 | while ((ptr != end) && (*ptr != '=') && (*ptr != '>') && (*ptr != '/') && isWhite(*ptr)) 379 | ++ptr; 380 | if (ptr == end) 381 | continue; 382 | 383 | switch(*ptr) { 384 | case '=': 385 | state = PreAttrValue; 386 | break; 387 | case '/': 388 | case '>': 389 | handler.onAttrEnd(); 390 | state = PreAttrName; 391 | continue; 392 | default: 393 | handler.onAttrEnd(); 394 | state = PreAttrName; 395 | start = ptr; 396 | continue; 397 | } 398 | break; 399 | 400 | case PreAttrValue: 401 | while ((ptr != end) && (*ptr != '\"') && (*ptr != '\'') && isWhite(*ptr)) 402 | ++ptr; 403 | if (ptr == end) 404 | continue; 405 | 406 | switch(*ptr) { 407 | case '\"': 408 | state = AttrValueDQ; 409 | start = ptr + 1; 410 | break; 411 | case '\'': 412 | state = AttrValueSQ; 413 | start = ptr + 1; 414 | break; 415 | default: 416 | state = AttrValueNQ; 417 | start = ptr; 418 | continue; 419 | } 420 | break; 421 | 422 | case AttrValueDQ: 423 | static if (ParseEntities) { 424 | while ((ptr != end) && (*ptr != '\"') && (*ptr != '&')) 425 | ++ptr; 426 | } else { 427 | while ((ptr != end) && (*ptr != '\"')) 428 | ++ptr; 429 | } 430 | if (ptr == end) 431 | continue; 432 | 433 | static if (ParseEntities) { 434 | auto noEntity = *ptr != '&'; 435 | } else { 436 | enum noEntity = true; 437 | } 438 | 439 | if (noEntity) { 440 | handler.onAttrValue(start[0..ptr-start]); 441 | handler.onAttrEnd(); 442 | state = PreAttrName; 443 | } else { 444 | static if (ParseEntities) { 445 | if (start != ptr) 446 | handler.onAttrValue(start[0..ptr-start]); 447 | saved = state; 448 | state = PreEntity; 449 | start = ptr; 450 | } 451 | } 452 | break; 453 | 454 | case AttrValueSQ: 455 | static if (ParseEntities) { 456 | while ((ptr != end) && (*ptr != '\'') && (*ptr != '&')) 457 | ++ptr; 458 | } else { 459 | while ((ptr != end) && (*ptr != '\'')) 460 | ++ptr; 461 | } 462 | if (ptr == end) 463 | continue; 464 | 465 | static if (ParseEntities) { 466 | auto noEntity = *ptr != '&'; 467 | } else { 468 | enum noEntity = true; 469 | } 470 | 471 | if (noEntity) { 472 | handler.onAttrValue(start[0..ptr-start]); 473 | handler.onAttrEnd(); 474 | state = PreAttrName; 475 | } else { 476 | static if (ParseEntities) { 477 | if (start != ptr) 478 | handler.onAttrValue(start[0..ptr-start]); 479 | saved = state; 480 | state = PreEntity; 481 | start = ptr; 482 | } 483 | } 484 | break; 485 | 486 | case AttrValueNQ: 487 | static if (ParseEntities) { 488 | while ((ptr != end) && (*ptr != '>') && (*ptr != '&') && !isWhite(*ptr)) 489 | ++ptr; 490 | } else { 491 | while ((ptr != end) && (*ptr != '>') && !isWhite(*ptr)) 492 | ++ptr; 493 | } 494 | if (ptr == end) 495 | continue; 496 | 497 | static if (ParseEntities) { 498 | auto noEntity = *ptr != '&'; 499 | } else { 500 | enum noEntity = true; 501 | } 502 | 503 | if (noEntity) { 504 | handler.onAttrValue(start[0..ptr-start]); 505 | handler.onAttrEnd(); 506 | state = PreAttrName; 507 | } else { 508 | static if (ParseEntities) { 509 | if (start != ptr) 510 | handler.onAttrValue(start[0..ptr-start]); 511 | saved = state; 512 | state = PreEntity; 513 | start = ptr; 514 | break; 515 | } 516 | } 517 | continue; 518 | 519 | case PreComment: 520 | if (*ptr == '-') { 521 | state = Comment; 522 | start = ptr + 1; 523 | } else { 524 | state = Declaration; 525 | } 526 | break; 527 | 528 | case Comment: 529 | while ((ptr != end) && (*ptr != '-')) 530 | ++ptr; 531 | if (ptr == end) 532 | continue; 533 | 534 | state = PostComment1; 535 | break; 536 | 537 | case PostComment1: 538 | state = (*ptr == '-') ? PostComment2 : Comment; 539 | break; 540 | 541 | case PostComment2: 542 | if (*ptr == '>') { 543 | handler.onComment(start[0..ptr-start-2]); 544 | state = Text; 545 | start = ptr + 1; 546 | } else if (*ptr != '-') { 547 | state = Comment; 548 | } 549 | break; 550 | 551 | case PreDeclaration: 552 | switch(*ptr) { 553 | case '[': 554 | state = PreCDATA; 555 | break; 556 | case '-': 557 | state = PreComment; 558 | break; 559 | default: 560 | state = Declaration; 561 | break; 562 | } 563 | break; 564 | 565 | case PreCDATA: 566 | if ((*ptr == 'C') || (*ptr == 'c')) { 567 | state = PreCDATA_C; 568 | } else { 569 | state = Declaration; 570 | continue; 571 | } 572 | break; 573 | 574 | case PreCDATA_C: 575 | if ((*ptr == 'D') || (*ptr == 'd')) { 576 | state = PreCDATA_CD; 577 | } else { 578 | state = Declaration; 579 | continue; 580 | } 581 | break; 582 | 583 | case PreCDATA_CD: 584 | if ((*ptr == 'A') || (*ptr == 'a')) { 585 | state = PreCDATA_CDA; 586 | } else { 587 | state = Declaration; 588 | continue; 589 | } 590 | break; 591 | 592 | case PreCDATA_CDA: 593 | if ((*ptr == 'T') || (*ptr == 't')) { 594 | state = PreCDATA_CDAT; 595 | } else { 596 | state = Declaration; 597 | continue; 598 | } 599 | break; 600 | 601 | case PreCDATA_CDAT: 602 | if ((*ptr == 'A') || (*ptr == 'a')) { 603 | state = PreCDATA_CDATA; 604 | } else { 605 | state = Declaration; 606 | continue; 607 | } 608 | break; 609 | 610 | case PreCDATA_CDATA: 611 | if (*ptr == '[') { 612 | state = CDATA; 613 | start = ptr + 1; 614 | } else { 615 | state = Declaration; 616 | continue; 617 | } 618 | break; 619 | 620 | case CDATA: 621 | while ((ptr != end) && (*ptr != ']')) 622 | ++ptr; 623 | if (ptr == end) 624 | continue; 625 | 626 | state = PostCDATA1; 627 | break; 628 | 629 | case PostCDATA1: 630 | state = (*ptr == ']') ? PostCDATA2 : CDATA; 631 | break; 632 | 633 | case PostCDATA2: 634 | if (*ptr == '>') { 635 | handler.onCDATA(start[0..ptr-start-2]); 636 | state = Text; 637 | start = ptr + 1; 638 | } else if (*ptr != ']') { 639 | state = CDATA; 640 | } 641 | break; 642 | 643 | case Declaration: 644 | while ((ptr != end) && (*ptr != '>')) 645 | ++ptr; 646 | if (ptr == end) 647 | continue; 648 | 649 | handler.onDeclaration(start[0..ptr-start]); 650 | state = Text; 651 | start = ptr + 1; 652 | break; 653 | 654 | case ProcessingInstruction: 655 | while ((ptr != end) && (*ptr != '>')) 656 | ++ptr; 657 | if (ptr == end) 658 | continue; 659 | 660 | handler.onProcessingInstruction(start[0..ptr-start]); 661 | state = Text; 662 | start = ptr + 1; 663 | break; 664 | 665 | case PreEntity: 666 | static if (ParseEntities) { 667 | if (*ptr == '#') { 668 | state = PreNumericEntity; 669 | break; 670 | } else { 671 | state = NamedEntity; 672 | continue; 673 | } 674 | } else { 675 | assert(0, "should never get here!"); 676 | } 677 | 678 | case NamedEntity: 679 | static if (ParseEntities) { 680 | while ((ptr != end) && (*ptr != ';') && isAlphaNum(*ptr) && (ptr - start < MaxEntityNameLength)) 681 | ++ptr; 682 | if (ptr == end) 683 | continue; 684 | 685 | if ((saved == Text) || (*ptr != '=')) { 686 | if (parseNamedEntity!(Handler, options)(start, ptr, handler)) { 687 | if (*start == ';') 688 | ++start; 689 | } 690 | } 691 | state = saved; 692 | 693 | if (*ptr == ';') break; 694 | else continue; 695 | } else { 696 | break; 697 | } 698 | 699 | case PreNumericEntity: 700 | static if (ParseEntities) { 701 | if ((*ptr == 'X') || (*ptr == 'x')) { 702 | state = HexEntity; 703 | break; 704 | } else { 705 | state = NumericEntity; 706 | continue; 707 | } 708 | } else { 709 | assert(0, "should never get here!"); 710 | } 711 | 712 | case NumericEntity: 713 | static if (ParseEntities) { 714 | while ((ptr != end) && (*ptr != ';') && isDigit(*ptr)) 715 | ++ptr; 716 | if (ptr == end) 717 | continue; 718 | 719 | state = saved; 720 | if (parseNumericEntity!(Handler, options)(start, ptr, handler)) { 721 | if (*start == ';') 722 | ++start; 723 | } 724 | 725 | if (*ptr == ';') break; 726 | else continue; 727 | } else { 728 | break; 729 | } 730 | 731 | case HexEntity: 732 | static if (ParseEntities) { 733 | while ((ptr != end) && (*ptr != ';') && isHexDigit(*ptr)) 734 | ++ptr; 735 | if (ptr == end) 736 | continue; 737 | 738 | state = saved; 739 | if (parseHexEntity!(Handler, options)(start, ptr, handler)) { 740 | if (*start == ';') 741 | ++start; 742 | } 743 | 744 | if (*ptr == ';') break; 745 | else continue; 746 | } else { 747 | break; 748 | } 749 | 750 | case PreScript_SC: 751 | if ((*ptr == 'r') || (*ptr == 'R')) { 752 | state = PreScript_SCR; 753 | } else { 754 | state = TagName; 755 | goto case TagName; 756 | } 757 | break; 758 | 759 | case PreScript_SCR: 760 | if ((*ptr == 'i') || (*ptr == 'I')) { 761 | state = PreScript_SCRI; 762 | } else { 763 | state = TagName; 764 | goto case TagName; 765 | } 766 | break; 767 | 768 | case PreScript_SCRI: 769 | if ((*ptr == 'p') || (*ptr == 'p')) { 770 | state = PreScript_SCRIP; 771 | } else { 772 | state = TagName; 773 | goto case TagName; 774 | } 775 | break; 776 | 777 | case PreScript_SCRIP: 778 | if ((*ptr == 't') || (*ptr == 't')) { 779 | state = PreScript_SCRIPT; 780 | } else { 781 | state = TagName; 782 | goto case TagName; 783 | } 784 | break; 785 | 786 | case PreScript_SCRIPT: 787 | if ((*ptr == '/') || (*ptr == '>') || isWhite(*ptr)) 788 | textState = ParserTextStates.Script; 789 | 790 | state = TagName; 791 | goto case TagName; 792 | 793 | case PreStyle_ST: 794 | if ((*ptr == 'y') || (*ptr == 'Y')) { 795 | state = PreStyle_STY; 796 | } else { 797 | state = TagName; 798 | goto case TagName; 799 | } 800 | break; 801 | 802 | case PreStyle_STY: 803 | if ((*ptr == 'l') || (*ptr == 'L')) { 804 | state = PreStyle_STYL; 805 | } else { 806 | state = TagName; 807 | goto case TagName; 808 | } 809 | break; 810 | 811 | case PreStyle_STYL: 812 | if ((*ptr == 'e') || (*ptr == 'E')) { 813 | state = PreStyle_STYLE; 814 | } else { 815 | state = TagName; 816 | goto case TagName; 817 | } 818 | break; 819 | 820 | case PreStyle_STYLE: 821 | if ((*ptr == '/') || (*ptr == '>') || isWhite(*ptr)) 822 | textState = ParserTextStates.Style; 823 | 824 | state = TagName; 825 | goto case TagName; 826 | 827 | case ClosingScript_SC: 828 | if ((*ptr == 'r') || (*ptr == 'R')) { 829 | state = ClosingScript_SCR; 830 | } else { 831 | state = Text; 832 | goto case Text; 833 | } 834 | break; 835 | 836 | case ClosingScript_SCR: 837 | if ((*ptr == 'i') || (*ptr == 'I')) { 838 | state = ClosingScript_SCRI; 839 | } else { 840 | state = Text; 841 | goto case Text; 842 | } 843 | break; 844 | 845 | case ClosingScript_SCRI: 846 | if ((*ptr == 'p') || (*ptr == 'p')) { 847 | state = ClosingScript_SCRIP; 848 | } else { 849 | state = Text; 850 | goto case Text; 851 | } 852 | break; 853 | 854 | case ClosingScript_SCRIP: 855 | if ((*ptr == 't') || (*ptr == 't')) { 856 | state = ClosingScript_SCRIPT; 857 | } else { 858 | state = Text; 859 | goto case Text; 860 | } 861 | break; 862 | 863 | case ClosingScript_SCRIPT: 864 | if ((*ptr == '>') || isWhite(*ptr)) { 865 | textState = ParserTextStates.Normal; 866 | state = ClosingTagName; 867 | start += 2; 868 | continue; 869 | } else { 870 | state = Text; 871 | goto case Text; 872 | } 873 | 874 | case ClosingStyle_ST: 875 | if ((*ptr == 'y') || (*ptr == 'Y')) { 876 | state = ClosingStyle_STY; 877 | } else { 878 | state = Text; 879 | goto case Text; 880 | } 881 | break; 882 | 883 | case ClosingStyle_STY: 884 | if ((*ptr == 'l') || (*ptr == 'L')) { 885 | state = ClosingStyle_STYL; 886 | } else { 887 | state = Text; 888 | goto case Text; 889 | } 890 | break; 891 | 892 | case ClosingStyle_STYL: 893 | if ((*ptr == 'e') || (*ptr == 'E')) { 894 | state = ClosingStyle_STYLE; 895 | } else { 896 | state = Text; 897 | goto case Text; 898 | } 899 | break; 900 | 901 | case ClosingStyle_STYLE: 902 | if ((*ptr == '>') || isWhite(*ptr)) { 903 | textState = ParserTextStates.Normal; 904 | state = ClosingTagName; 905 | start += 2; 906 | continue; 907 | } else { 908 | state = Text; 909 | goto case Text; 910 | } 911 | } 912 | 913 | ++ptr; 914 | } 915 | 916 | auto remaining = start[0..ptr-start]; 917 | if (!remaining.empty) { 918 | switch(state) with (ParserStates) { 919 | case Comment: 920 | handler.onComment(remaining); 921 | break; 922 | case PostComment1: 923 | handler.onComment(remaining[0..$-1]); 924 | break; 925 | case PostComment2: 926 | handler.onComment(remaining[0..$-2]); 927 | break; 928 | case NamedEntity: 929 | static if (ParseEntities) { 930 | if (saved == Text) { 931 | if (ptr-start > 1) 932 | parseNamedEntity!(Handler, options)(start, ptr, handler); 933 | if (start < ptr) 934 | handler.onText(start[0..ptr-start]); 935 | } 936 | } 937 | break; 938 | case NumericEntity: 939 | static if (ParseEntities) { 940 | if (saved == Text) { 941 | if (ptr-start > 2) 942 | parseNumericEntity!(Handler, options)(start, ptr, handler); 943 | if (start < ptr) 944 | handler.onText(start[0..ptr-start]); 945 | } 946 | } 947 | break; 948 | case HexEntity: 949 | static if (ParseEntities) { 950 | if (saved == Text) { 951 | if (ptr-start > 3) 952 | parseHexEntity!(Handler, options)(start, ptr, handler); 953 | if (start < ptr) 954 | handler.onText(start[0..ptr-start]); 955 | } 956 | } 957 | break; 958 | default: 959 | if ((state != TagName) && 960 | (state != PreAttrName) && 961 | (state != PreAttrValue) && 962 | (state != PostAttrName) && 963 | (state != AttrName) && 964 | (state != AttrValueDQ) && 965 | (state != AttrValueSQ) && 966 | (state != AttrValueNQ) && 967 | (state != ClosingTagName)) { 968 | handler.onText(remaining); 969 | } 970 | break; 971 | } 972 | } 973 | 974 | handler.onDocumentEnd(); 975 | } 976 | -------------------------------------------------------------------------------- /src/html/entities.d: -------------------------------------------------------------------------------- 1 | module html.entities; 2 | 3 | import std.algorithm; 4 | import std.conv; 5 | import std.utf; 6 | 7 | 8 | enum MinEntityNameLength = 2; 9 | enum MaxEntityNameLength = 31; 10 | enum MaxLegacyEntityNameLength = 6; 11 | 12 | 13 | package enum EntityIndexDef = `["nrtri":12307,"downharpoonright":22867,"harrw":42131,"Bernoullis":9587,"hArr":2035,"colon":44257,"TScy":2962,"rbrke":44547,"naturals":2739,"quatint":35571,"orarr":45459,"cupcup":6323,"coprod":7379,"ecir":6275,"Vopf":7428,"divide":10370,"DownTee":39427,"Umacr":47618,"block":48403,"Sacute":12354,"barwed":14307,"jcirc":49746,"GJcy":13730,"nrtrie":15027,"Succeeds":13635,"cupdot":16339,"horbar":17011,"NotSucceeds":12851,"Rarrtl":17427,"comma":52625,"thorn":52818,"rsaquo":19251,"Iogon":53298,"lvertneqq":23062,"NotNestedGreaterGreater":67269,"complement":34883,"scap":21603,"csube":55363,"vBar":21827,"rtimes":23539,"xuplus":24483,"Implies":24771,"approx":12083,"jmath":56850,"LeftRightArrow":19747,"ngeq":25059,"nges":25221,"ThickSpace":65446,"backprime":1315,"Ucirc":58834,"Backslash":14499,"RightVector":27187,"efDot":60451,"bigtriangleup":37507,"vArr":14979,"wedgeq":31395,"blacktriangle":54675,"Abreve":32418,"NotLeftTriangleEqual":3779,"Tcedil":32866,"iacute":33186,"Hscr":32483,"frac12":34114,"frac13":34339,"frac14":34418,"utrif":54675,"frac15":34595,"frac16":34691,"dopf":33956,"Atilde":35250,"frac18":35203,"edot":34386,"scnE":34739,"frac23":36003,"vsupnE":36502,"frac25":36451,"SupersetEqual":25587,"vrtri":38451,"frac34":37954,"frac35":38035,"lstrok":38322,"frac38":38547,"downharpoonleft":14931,"order":20515,"isinsv":39379,"mscr":38756,"frac45":39779,"parsl":57587,"NegativeThickSpace":2323,"vsupne":41078,"frac56":41363,"frac58":41539,"NegativeVeryThinSpace":2323,"csupe":68627,"frac78":43731,"there4":20163,"NotGreater":6675,"cirmid":44499,"circlearrowleft":11763,"NotPrecedesEqual":18997,"fjlig":4834,"cudarrl":64099,"TildeEqual":9939,"ngtr":6675,"cudarrr":64547,"iiota":7331,"Longrightarrow":25379,"blacktriangleleft":23203,"RightDownTeeVector":20803,"DoubleLeftArrow":28227,"ShortLeftArrow":40195,"Delta":13394,"nsmid":14259,"omicron":450,"bkarow":1267,"Mopf":50292,"nbumpe":9205,"rpar":50913,"trisb":17987,"Vscr":53764,"sect":43618,"LeftTriangle":24435,"ropf":54724,"sdot":55123,"subedot":8659,"barwedge":14307,"aelig":2178,"eqslantgtr":45299,"longrightarrow":19395,"CircleMinus":30547,"leftarrow":40195,"curvearrowleft":5459,"uwangle":16771,"zeetrf":14547,"caret":28419,"lneqq":11811,"uplus":29123,"trpezium":51875,"DoubleRightTee":30019,"imof":61219,"setmn":14499,"nwArr":30163,"LeftArrow":40195,"colone":39091,"DownRightVector":25299,"semi":62849,"nwarrow":23747,"OverBar":24003,"njcy":63186,"gtlPar":63427,"gtrsim":2867,"bcong":8131,"isinE":35155,"seArr":35827,"Hcirc":36178,"kappav":29458,"Cacute":65122,"ZHcy":64754,"nisd":65811,"Rcaron":67714,"Udblac":67970,"succeq":21235,"isins":41731,"thetav":29922,"isinv":3875,"hairsp":275,"varsigma":33154,"caron":11538,"Epsilon":32274,"NotRightTriangleEqual":15027,"acE":43653,"emacr":43954,"cularrp":33219,"dscr":2452,"kappa":44322,"TRADE":16387,"dscy":3922,"LJcy":4146,"cularr":5459,"Nacute":6882,"iocy":7682,"IJlig":46482,"weierp":8451,"LessSlantEqual":483,"acd":46579,"mumap":46915,"OpenCurlyQuote":51651,"wreath":9987,"precneqq":42995,"LeftUpVector":30499,"LeftTeeArrow":23443,"minusdu":40371,"SucceedsTilde":1507,"sext":11267,"prnsim":12611,"acy":48498,"emsp13":12803,"emsp14":13043,"NotGreaterLess":10995,"xcap":4051,"Wedge":35779,"lmidot":14674,"mapstoup":11043,"bullet":16483,"nspar":13987,"afr":51060,"vartriangleright":38451,"CHcy":17698,"Yacute":19218,"epsiv":25554,"LeftTee":45667,"LowerRightArrow":29795,"ssetmn":14499,"HumpEqual":9203,"ecirc":7026,"Dopf":21652,"Edot":22194,"dsol":23651,"triangleq":18579,"fpartint":21971,"Mscr":25715,"apE":10579,"ImaginaryI":10899,"InvisibleComma":33379,"iopf":26660,"and":41315,"amp":17777,"ang":12899,"RightTeeVector":44451,"pound":7810,"nldr":29219,"bcy":60722,"uharl":30499,"ape":33427,"uharr":45203,"DoubleLongLeftRightArrow":35331,"rscr":30388,"nLeftarrow":15939,"nleq":30451,"nles":30677,"shcy":31362,"YUcy":31522,"iota":31602,"scaron":32690,"hellip":33027,"TildeFullEqual":47779,"bfr":62788,"submult":56419,"DownArrowUpArrow":6131,"DownArrow":36883,"xlarr":36723,"DD":46307,"ast":64369,"integers":33715,"uhblk":64883,"iiiint":2403,"Gbreve":38722,"oacute":39474,"ubrcy":66434,"ncongdot":38869,"cap":323,"dArr":37027,"Cayleys":16627,"GT":40289,"bne":884,"ffllig":43987,"xcup":37411,"dtri":13315,"npreceq":18997,"lesseqgtr":3,"Gg":59779,"nsupseteq":1059,"swarrow":17731,"Ropf":4387,"looparrowleft":1459,"bot":2787,"Product":46771,"Gt":5875,"iinfin":47059,"zacute":47234,"aogon":8338,"harrcir":65539,"breve":9394,"Im":27907,"cfr":9524,"rsqb":47409,"NotGreaterTilde":17331,"rrarr":9891,"dotminus":6051,"LT":46289,"eqcirc":6275,"wopf":48612,"chi":11634,"divonx":47923,"nmid":14259,"tilde":12274,"oast":27315,"nesim":13093,"bigwedge":35779,"eqvparsl":48323,"Ll":64435,"cir":15171,"Lt":20851,"copysr":53027,"RightTriangleBar":17843,"Mu":66258,"ldquo":18899,"Nu":67346,"nvrArr":55011,"twixt":21459,"Or":68035,"Pi":68258,"vnsub":22582,"sime":9939,"Pr":835,"simg":56211,"siml":56579,"Barwed":9155,"Re":2995,"vnsup":11366,"nparsl":57590,"dcy":24738,"HARDcy":57922,"succneqq":34739,"Sc":4739,"deg":25346,"CenterDot":7154,"trianglelefteq":23155,"longmapsto":11091,"gEl":27027,"intprod":16723,"dfr":27748,"cuepr":28275,"rArr":24771,"ForAll":14179,"larrbfs":18627,"NoBreak":19587,"rtri":22099,"backsim":20755,"die":11458,"cuesc":6915,"SucceedsSlantEqual":4995,"Dscr":61748,"ocir":62371,"NotSucceedsTilde":1509,"div":10370,"Xi":15138,"times":12738,"cup":29555,"igrave":48962,"plusacir":62099,"gneqq":3955,"iscr":64484,"Integral":3411,"umacr":39186,"lbrksld":27955,"Equal":40547,"subnE":26211,"ecy":41410,"lbrkslu":30067,"dot":14418,"asympeq":30931,"Iacute":242,"neArr":42371,"dollar":817,"Ccirc":42786,"dlcorn":1363,"dotplus":32723,"SquareSubset":33859,"mstpos":3571,"fflig":43827,"efr":44068,"subne":13459,"isin":3875,"leqslant":483,"minusb":5763,"iogon":45026,"ac":3571,"minusd":6051,"LessTilde":11171,"egs":45299,"Lstrok":6450,"af":28979,"LeftUpTeeVector":43347,"Lleftarrow":32115,"subset":8291,"ap":12083,"succcurlyeq":4995,"upsih":47202,"odiv":8755,"ijlig":47330,"isindot":39635,"Cconint":40243,"lozenge":22355,"dd":18211,"npart":48245,"gE":3043,"ccaps":48451,"mapstodown":47363,"Iopf":12500,"ee":34787,"eg":35283,"ell":49651,"subsim":14627,"npar":13987,"GreaterSlantEqual":25219,"el":35875,"LeftDownTeeVector":46867,"els":23955,"DownRightTeeVector":14083,"ucirc":14850,"leftleftarrows":12131,"eng":51346,"ge":21923,"parallel":1795,"gg":5875,"ccaron":18178,"nsubE":43877,"Rscr":17379,"gl":33475,"qprime":18851,"Iota":19122,"nopf":19156,"gt":40289,"fcy":53522,"TripleDot":10275,"odot":19923,"ic":33379,"lE":17603,"RightDownVector":22867,"ii":10899,"erarr":54963,"in":3875,"it":9107,"nsube":53715,"ffr":56356,"varsubsetneq":13462,"ReverseElement":18435,"wscr":23588,"nsucc":12851,"loang":57091,"le":1987,"COPY":4914,"lg":15619,"eta":57682,"ll":20851,"Vdashl":26435,"eth":37874,"exponentiale":34787,"lt":46289,"oS":27107,"lessapprox":61107,"mp":36259,"ne":46675,"ncaron":28546,"ni":18435,"mu":47266,"UpperRightArrow":4099,"disin":60403,"circledR":26994,"nu":48018,"circledS":27107,"or":16115,"DownTeeArrow":47363,"subsub":31555,"pi":48882,"SOFTcy":31874,"gap":8499,"pm":49570,"loarr":62147,"mdash":62323,"NotNestedLessLess":59109,"pr":31635,"subsup":33523,"supset":11363,"gesdotol":31683,"sc":13635,"xwedge":35779,"SubsetEqual":10803,"gcy":63970,"emsp":36083,"rx":53331,"angmsd":37907,"gel":5187,"leftthreetimes":42883,"geq":21923,"RightArrowBar":26083,"ges":25219,"napid":65637,"npre":18997,"Wopf":38996,"nsupE":30597,"supsim":40499,"ggg":59779,"gfr":66468,"lesdot":41683,"delta":67570,"Colone":42531,"lsime":67923,"lsimg":68131,"gimel":68179,"glE":68435,"slarr":40195,"vartheta":29922,"wp":8451,"wr":9987,"xi":58130,"nsupe":1059,"GreaterEqualLess":5187,"uacute":44178,"smid":26483,"spadesuit":44899,"boxtimes":26723,"gnE":3955,"iuml":44994,"gla":5091,"bigsqcup":28835,"dzcy":45586,"THORN":5506,"lobrk":6771,"glj":6723,"inodot":46450,"tshcy":8050,"commat":47649,"napos":9314,"gne":9475,"lrtri":9795,"NotSupersetEqual":1059,"dlcrop":48195,"rarrbfs":67219,"bigcirc":19443,"ensp":49603,"kcedil":50498,"Superset":11363,"shchcy":52050,"boxbox":52003,"LeftVectorBar":34547,"supsub":52979,"hfr":17060,"NotSuperset":11366,"dHar":52499,"shortparallel":1795,"updownarrow":99,"RightUpVectorBar":17795,"NotElement":15219,"ddotseq":5411,"dbkarow":6483,"supsup":54211,"Leftarrow":28227,"tbrk":54259,"epar":54627,"rbrksld":9635,"hslash":6227,"OverBrace":36403,"smte":22915,"Iscr":6579,"Lmidot":57330,"rbrkslu":12563,"hcirc":25186,"eopf":57796,"realpart":2995,"UnderBar":12481,"nsce":21237,"forkv":27859,"diamond":16963,"hercon":60755,"udarr":26579,"nscr":60340,"ogon":61074,"triminus":52451,"icy":30322,"LeftVector":20307,"blacktriangleright":29843,"clubsuit":8979,"lAarr":32115,"dfisht":62899,"iff":2035,"lEg":15699,"DownBreve":5330,"ifr":34020,"xharr":25427,"diamondsuit":1891,"rightrightarrows":9891,"Uring":37218,"lesges":65187,"Scirc":37378,"ntilde":55314,"nsim":56259,"EmptyVerySmallSquare":48787,"ograve":55410,"intcal":58739,"wedge":41315,"Scaron":68546,"InvisibleTimes":9107,"imagpart":27907,"DoubleUpDownArrow":14979,"dotsquare":52339,"complexes":59379,"rHar":147,"solb":723,"pitchfork":19971,"Nopf":2739,"bigcap":4051,"spar":1795,"epsi":5698,"int":3411,"PlusMinus":49570,"jcy":46114,"Oacute":8018,"propto":7971,"Wscr":8228,"vBarv":47011,"fallingdotseq":60451,"sopf":9732,"Upsilon":39858,"tdot":10275,"jfr":48132,"ntgl":10995,"RightTee":21187,"yacy":12770,"hookrightarrow":28691,"strns":14226,"backsimeq":8931,"nsub":14883,"leftrightarrows":14371,"nsup":17203,"SuchThat":18435,"ZeroWidthSpace":2323,"Zacute":20578,"HumpDownHump":2915,"ntlg":19875,"supsetneqq":24387,"ulcorn":21315,"angmsdaa":18531,"angmsdab":18675,"angmsdac":19075,"angmsdad":19347,"angmsdae":19539,"ltrPar":23395,"angmsdaf":19795,"angmsdag":20067,"angmsdah":20259,"DownLeftTeeVector":18947,"Downarrow":37027,"succsim":1507,"oint":24579,"OElig":57410,"kcy":58002,"DotDot":26851,"RightUpDownVector":56739,"xmap":11091,"vartriangleleft":24435,"homtht":27811,"xsqcup":28835,"SucceedsEqual":21235,"compfn":29171,"kfr":60212,"eacute":29762,"SquareSuperset":3251,"nGg":61413,"nGt":62470,"lfloor":33107,"Iuml":32450,"tcaron":33682,"hstrok":34082,"rationals":16531,"dtdot":63219,"escr":35107,"gesdot":37123,"bigcup":37411,"Dashv":48051,"therefore":20163,"nvap":37558,"UpTeeArrow":11043,"lap":61107,"lat":65715,"nLl":65861,"nLt":66790,"SquareSupersetEqual":6179,"lgE":67411,"varpi":67090,"lcy":68226,"sqcap":5235,"leg":3,"DoubleVerticalBar":1795,"Igrave":43586,"esim":5363,"ltcir":1667,"leq":1987,"les":483,"ngeqq":3045,"nvge":44358,"reals":4387,"lfr":4644,"sccue":4995,"eqsim":5363,"nvgt":45860,"Rrightarrow":1107,"natur":7763,"gsime":7923,"ntrianglelefteq":3779,"plusdo":32723,"nlarr":8707,"NegativeThinSpace":2323,"gsiml":9059,"ContourIntegral":24579,"andand":47667,"plusdu":47971,"lmoustache":4003,"Eopf":47828,"check":10947,"napprox":32339,"lesseqqgtr":15699,"lnE":11811,"Congruent":39683,"squf":27667,"nvle":49158,"notin":15219,"map":15459,"nvlt":50628,"suphsol":1715,"Nscr":50852,"xnis":51603,"angsph":52691,"jopf":52084,"lne":2131,"iexcl":17570,"lnsim":18355,"micro":18402,"Subset":53827,"UpArrow":5539,"xcirc":19443,"twoheadrightarrow":46723,"mcy":21042,"curvearrowright":29363,"expectation":22675,"sscr":55508,"loz":22355,"Gamma":22834,"notni":23347,"suphsub":11715,"mfr":24276,"plusmn":49570,"lrm":25139,"lsh":25763,"lambda":58626,"shortmid":26483,"Cedilla":15266,"mho":26531,"mid":26483,"NotGreaterEqual":25059,"andd":58867,"Ccaron":59426,"leftharpoondown":16851,"capand":59539,"ulcrop":59587,"bsemi":27395,"IEcy":59906,"andv":60499,"nwnear":61027,"mnplus":36259,"ccirc":31170,"pointint":53427,"ltdot":31123,"ange":61859,"QUOT":36865,"bdquo":21363,"bbrk":60931,"itilde":62866,"nap":32339,"ExponentialE":34787,"sqcup":32531,"EmptySmallSquare":51011,"star":63475,"ngE":3045,"realine":17379,"lagran":23251,"ncy":37250,"Sopf":64692,"Ncaron":65234,"Leftrightarrow":2035,"para":59874,"sqsubseteq":15859,"precnsim":12611,"ultri":39987,"asymp":12083,"ltlarr":67123,"nge":25059,"sharp":40979,"nfr":40708,"Prime":41955,"part":29411,"DJcy":68338,"equiv":39683,"ngt":6675,"capcap":531,"xopf":68484,"omid":68675,"udhar":13219,"nlE":43269,"Supset":2563,"profalar":61811,"euml":2370,"bowtie":3667,"rightarrowtail":46019,"gtrless":33475,"Vvdash":4339,"ugrave":4530,"nis":44707,"niv":18435,"subE":6371,"nle":30451,"ufisht":8403,"NewLine":37649,"varsupsetneq":41078,"NotSucceedsEqual":21237,"ruluhar":39299,"nlt":24531,"curarrm":41235,"sube":10803,"Iukcy":48674,"euro":12691,"lescc":49299,"succ":13635,"leftrightarrow":19747,"Uacute":14754,"bernou":9587,"ocy":50098,"nleqslant":30677,"longleftrightarrow":25427,"sqsube":15859,"ShortUpArrow":5539,"not":47890,"tint":16163,"npr":51,"cupor":52643,"dcaron":19842,"ofr":53236,"thksim":14131,"nsc":12851,"sbquo":54307,"ogt":54467,"upharpoonright":45203,"ohm":35970,"flat":22435,"Escr":22675,"PartialD":29411,"aopf":23892,"num":57025,"Kcedil":25522,"RightArrow":7059,"subseteq":10803,"nparallel":13987,"UpEquilibrium":13219,"supedot":50243,"oelig":58594,"heartsuit":54835,"sup1":27074,"sup2":27234,"sup3":27362,"jscr":27492,"NotGreaterSlantEqual":25221,"par":1795,"olt":59667,"khcy":28514,"curarr":29363,"apid":29027,"supE":29651,"nsucceq":21237,"Esim":30211,"sung":31283,"conint":24579,"pcy":62194,"capcup":34931,"supe":25587,"bumpeq":9203,"lsquo":51651,"VerticalSeparator":46819,"ord":63379,"pfr":63668,"numero":36675,"lbarr":64179,"approxeq":33427,"sqsupe":6179,"Sqrt":8179,"DoubleContourIntegral":63555,"nleqq":43269,"phi":64850,"orv":65075,"Union":37411,"Amacr":65330,"UpTee":2787,"rfloor":4595,"zcaron":39954,"trianglerighteq":3619,"apos":40641,"nless":24531,"eDot":40659,"piv":67090,"excl":40913,"rightharpoonup":27187,"PrecedesSlantEqual":20019,"jsercy":42754,"capdot":43043,"Barv":42707,"maltese":55795,"Jopf":42932,"opar":43539,"blacklozenge":49347,"Because":7283,"beta":44866,"Laplacetrf":23251,"Ntilde":45922,"beth":45507,"Sscr":45956,"prE":6627,"oopf":46516,"Ograve":47298,"gtcir":10403,"langd":10851,"empty":11667,"pre":11859,"lbbrk":12035,"qfr":12212,"xscr":49044,"succnsim":36211,"Acirc":13906,"psi":14594,"nGtv":5877,"lcedil":51378,"bsime":8931,"AMP":17777,"precnapprox":20707,"xrarr":19395,"prcue":20019,"lnapprox":51747,"telrec":55219,"nsubseteqq":43877,"RightDownVectorBar":20355,"Equilibrium":16067,"Star":56019,"ofcir":23299,"kjcy":56658,"gnsim":25635,"rightsquigarrow":13827,"uring":25810,"scirc":25954,"rdquo":26339,"rcy":26626,"reg":26994,"intercal":58739,"Xopf":60660,"rfr":29956,"egrave":61586,"nshortparallel":13987,"perp":2787,"nsccue":4867,"crarr":31027,"Euml":61618,"yicy":62018,"rho":32386,"thetasym":29922,"ascr":62948,"uarr":5539,"square":44211,"squarf":27667,"Imacr":35074,"scE":36131,"fnof":64146,"Longleftrightarrow":35331,"xutri":37507,"gtdot":38403,"otilde":63522,"supmult":27555,"Eacute":63602,"rlm":38947,"gesles":66563,"lsquor":54307,"pertenk":28179,"llhard":66707,"rightharpoondown":25299,"sce":21235,"GreaterLess":33475,"ordf":63762,"Tcaron":642,"ordm":63842,"Hstrok":1154,"bprime":1315,"szlig":35746,"supnE":24387,"scy":43186,"aleph":43395,"Exists":4243,"HorizontalLine":57139,"sfr":45796,"nharr":46243,"supne":41075,"rsh":46627,"Aopf":8596,"Icirc":36370,"subsetneqq":26211,"drcorn":11219,"sim":14131,"shy":48098,"profsurf":66659,"drbkarow":9683,"Jscr":13764,"tridot":15507,"fopf":15076,"Vdash":50579,"gdot":15666,"gesdoto":44131,"CircleDot":19923,"apacir":17891,"duarr":6131,"tau":52546,"LeftTriangleBar":15987,"epsilon":5698,"awconint":771,"Acy":53202,"esdot":1587,"smt":53587,"precsim":37171,"otimes":10147,"fork":19971,"oscr":20515,"gescc":54787,"sol":55345,"oror":21875,"ecolon":22723,"tcy":55442,"supdsub":47475,"Afr":56068,"triangledown":13315,"lBarr":56531,"toea":23795,"cuvee":17939,"plusb":57491,"lopar":57715,"tfr":57860,"pluse":57955,"LeftAngleBracket":32035,"squ":44211,"dashv":45667,"xvee":20659,"nequiv":28099,"fllig":59283,"lurdshar":25907,"sub":8291,"phiv":3458,"sum":61267,"sup":11363,"centerdot":7154,"CupCap":30931,"phone":61971,"roang":62051,"curlyeqsucc":6915,"lang":32035,"Beta":32194,"And":62659,"Alpha":62754,"ffilig":33267,"ccupssm":56691,"bigotimes":20211,"Lambda":35714,"Oopf":35508,"Bcy":63634,"geqq":3043,"RightVectorBar":44275,"nsubset":22582,"osol":37459,"gesl":38086,"ucy":65410,"quest":65617,"top":39427,"Bfr":66036,"roarr":66211,"Eogon":66530,"Xscr":39892,"larr":40195,"rnmid":67043,"cuwed":40931,"topf":41172,"LowerLeftArrow":17731,"late":34147,"Itilde":42418,"ufr":67780,"xlArr":38355,"Intersection":4051,"varkappa":29458,"nvltrie":62230,"nprec":51,"auml":42674,"GreaterGreater":40083,"tstrok":44754,"tosa":35027,"parsim":44819,"orderof":20515,"Uparrow":10499,"UpperLeftArrow":23747,"laquo":5586,"scnap":5651,"ENG":5730,"larrsim":64291,"Cap":7235,"radic":8179,"clubs":8979,"gamma":9282,"questeq":50531,"Mellintrf":25715,"hyphen":36979,"uml":11458,"Hacek":11538,"numsp":11939,"TSHcy":13426,"Ugrave":50978,"eparsl":51299,"vcy":15794,"robrk":8803,"vee":16115,"vangrt":52579,"Cfr":16627,"NotDoubleVerticalBar":13987,"ETH":16818,"Sigma":17122,"vzigzag":4291,"smallsetminus":14499,"bsolhsub":50355,"larrb":18035,"Chi":18770,"drcrop":54115,"vfr":20404,"Ascr":54516,"NotHumpEqual":9205,"Uarr":54915,"rcedil":55986,"nLtv":55573,"SquareIntersection":5235,"nLeftrightarrow":49955,"doteq":1587,"nsupset":11366,"NotRightTriangleBar":40421,"srarr":7059,"fscr":58196,"ldca":58499,"NJcy":58914,"equivDD":16579,"Dcaron":60098,"tritime":17523,"lesdoto":17475,"oslash":60578,"scpolint":50739,"ouml":60274,"RightTriangle":38451,"Dcy":29890,"prime":30115,"xotime":20211,"Del":31203,"geqslant":25219,"CounterClockwiseContourIntegral":771,"multimap":46915,"Dfr":33316,"lates":34150,"nshortmid":14259,"LessLess":59107,"DiacriticalDot":14418,"wfr":36804,"varphi":3458,"NotLessLess":55573,"lcub":50225,"bsolb":37827,"nleftrightarrow":46243,"DScy":65586,"mapsto":15459,"Cup":40035,"rAarr":1107,"sqsubset":33859,"DoubleDot":11458,"dblac":22482,"iukcy":40770,"bepsi":41282,"IOcy":67378,"Conint":63555,"ubreve":68002,"divideontimes":47923,"DoubleLeftTee":48051,"Fopf":67604,"VDash":41779,"trie":18579,"Gdot":67842,"caps":326,"nprcue":1411,"nbump":31797,"loplus":2243,"utilde":2290,"Bumpeq":2915,"LeftDownVector":14931,"blacktriangledown":58035,"rsquor":3491,"Ycirc":44034,"DoubleLongLeftArrow":38355,"sqcaps":5238,"Oscr":4180,"GreaterFullEqual":3043,"lessdot":31123,"Cross":45619,"kopf":5812,"Ecy":45762,"Dot":11458,"Zcaron":8370,"rppolint":64243,"subseteqq":6371,"imagline":6579,"nRightarrow":18259,"Efr":47716,"tscr":10740,"Jsercy":12178,"backcong":8131,"ldsh":11491,"tscy":11906,"Rightarrow":24771,"minus":49699,"xfr":49844,"LeftUpVectorBar":43219,"vprop":7971,"Lang":19699,"ecaron":21074,"NotSucceedsSlantEqual":4867,"llarr":12131,"HilbertSpace":32483,"RightUpVector":45203,"gjcy":22226,"RightTeeArrow":15459,"SHcy":25026,"LeftDownVectorBar":39219,"DownRightVectorBar":13683,"Fcy":57762,"Lcedil":26178,"NotEqualTilde":13093,"dtrif":58035,"aacute":2834,"sqsupset":3251,"amacr":58706,"Larr":26899,"urcorn":28323,"Topf":27604,"ycy":59458,"leqq":17603,"Ffr":60036,"yen":59218,"lesg":29270,"Auml":3330,"CloseCurlyDoubleQuote":26339,"dstrok":30290,"rarrsim":53923,"Eta":61490,"longleftarrow":36723,"yfr":61684,"hkswarow":28787,"duhar":18803,"NotTildeTilde":32339,"varrho":20994,"sigmaf":33154,"nsubseteq":53715,"yopf":32772,"zdot":33074,"incare":34291,"CloseCurlyQuote":3491,"Uogon":63154,"ngsim":17331,"sigmav":33154,"luruhar":57363,"lacute":36642,"frasl":63923,"bnot":36595,"rdldhar":58355,"plus":37281,"nesear":23795,"ccups":65363,"amalg":65763,"kgreen":40338,"Egrave":4706,"nVdash":40595,"LongRightArrow":19395,"smile":61363,"FilledVerySmallSquare":27667,"prurel":42051,"DotEqual":1587,"acirc":45122,"Gcy":67746,"RBarr":9683,"VeryThinSpace":275,"Square":44211,"looparrowright":35619,"NotLeftTriangle":10691,"zcy":2610,"OverParenthesis":31939,"Gfr":3716,"ntrianglerighteq":15027,"ndash":4787,"NotLessTilde":58451,"nsupseteqq":30597,"Otilde":5618,"zfr":7572,"NotRightTriangle":12307,"Fscr":48531,"odsold":49395,"bigtriangledown":53379,"simplus":67667,"bopf":49444,"cdot":49778,"LeftArrowRightArrow":14371,"Hat":15553,"Ouml":6418,"zeta":51266,"elsdot":52771,"swarr":17731,"kscr":52916,"pluscir":5139,"NotReverseElement":23347,"varepsilon":25554,"NotCongruent":28099,"prnap":20707,"origof":55059,"CirclePlus":22259,"angrtvb":8083,"triangleright":22099,"boxH":55939,"ltrie":23155,"ltrif":23203,"Hfr":23843,"subplus":11315,"imacr":24146,"zigrarr":11987,"boxV":57043,"nexists":13171,"Therefore":20163,"boxminus":5763,"swnwar":58659,"GreaterTilde":2867,"scsim":1507,"iprod":16723,"Uarrocir":63043,"boxh":57139,"lessgtr":15619,"half":34114,"image":27907,"boxv":59987,"Otimes":60835,"hbar":6227,"LeftFloor":33107,"triangle":51699,"cent":7890,"ssmile":61363,"RightDoubleBracket":8803,"DiacriticalAcute":12658,"nrarr":31987,"Kopf":63092,"erDot":8547,"zwj":33907,"urcrop":63795,"doteqdot":40659,"NotLessGreater":19875,"Icy":36770,"DiacriticalDoubleAcute":22482,"Tscr":65268,"NotLessSlantEqual":30677,"harr":19747,"midast":64369,"ClockwiseContourIntegral":2691,"icirc":39266,"ShortRightArrow":7059,"popf":66148,"UnderParenthesis":41587,"Ifr":27907,"xhArr":35331,"varnothing":11667,"rightleftarrows":30979,"vdash":21187,"yscr":580,"zhcy":2210,"gnap":4483,"gammad":6098,"imath":46450,"roplus":9427,"ncong":19299,"bnequiv":39686,"risingdotseq":8547,"npolint":40803,"gneq":9475,"Int":48995,"forall":14179,"ljcy":13362,"downdownarrows":21107,"succnapprox":5651,"Jcy":49810,"Tstrok":15426,"operp":50403,"fltns":50691,"midcir":18307,"Theta":52738,"Jfr":52852,"bigvee":20659,"Yopf":20932,"Gcedil":21794,"Zdot":21154,"dharl":14931,"alpha":55474,"dharr":22867,"urtri":56307,"NotTildeFullEqual":19299,"precapprox":17251,"cylcty":24979,"exist":4243,"bscr":24676,"Aring":48578,"varr":99,"upsilon":13938,"chcy":25682,"rightthreetimes":56131,"nVDash":27267,"nlsim":58451,"backepsilon":41282,"orslope":51923,"eogon":59634,"DoubleLongRightArrow":25379,"capbrcup":26035,"sqsub":33859,"prap":17251,"SHCHcy":30354,"Rcedil":31250,"gacute":31490,"sqsup":3251,"Kcy":61650,"dzigrarr":29075,"DownLeftVectorBar":18483,"NotSquareSupersetEqual":14707,"bsim":20755,"cedil":15266,"emptyv":11667,"prec":31635,"bigoplus":16259,"eDDot":5411,"Kfr":63316,"langle":32035,"RoundImplies":50451,"cwint":63875,"eqslantless":23955,"Oslash":13554,"yucy":39346,"DZcy":39602,"between":21459,"Bopf":40132,"Omicron":60546,"Cdot":40306,"lceil":66611,"racute":42098,"boxplus":57491,"bsol":41937,"lAtail":42579,"rsquo":3491,"Zeta":42226,"NestedLessLess":20851,"Poincareplane":23843,"prnE":42995,"nsqsube":48915,"rbarr":1267,"middot":7154,"Kscr":43476,"CircleTimes":10147,"sigma":3122,"gopf":44644,"dagger":45155,"vellip":45347,"quaternions":49907,"macr":14226,"Lcy":7538,"prod":46771,"pscr":47140,"Ubreve":48370,"prop":7971,"Lfr":11572,"hoarr":12995,"yuml":14786,"Utilde":50002,"DownLeftVector":16851,"NonBreakingSpace":35426,"NotTilde":56259,"NotLeftTriangleBar":15989,"RightTriangleEqual":3619,"nlArr":15939,"nvHarr":52147,"lhard":16851,"mapstoleft":23443,"curlywedge":40931,"nltri":10691,"NotSubset":22582,"notinE":53637,"iquest":15394,"cirE":53475,"lharu":20307,"rangd":20467,"male":54067,"range":20611,"rbbrk":21411,"Map":22307,"malt":55795,"Gcirc":22514,"curren":15826,"scedil":56498,"raemptyv":46963,"circ":56466,"cire":28051,"SmallCircle":29171,"egsdot":57443,"nwarr":23747,"olarr":11763,"lhblk":26131,"nsqsupe":14707,"profline":48739,"Mcy":26258,"Popf":58307,"agrave":16306,"subsetneq":13459,"leftarrowtail":41827,"Ecaron":60802,"NotSquareSubset":51797,"Mfr":29492,"searr":29795,"vDash":30019,"Yscr":61156,"Lsh":25763,"EqualTilde":5363,"uopf":61908,"mDDot":31443,"bull":16483,"emptyset":11667,"LeftCeiling":66611,"ycirc":32834,"swarhk":28787,"bump":2915,"Aacute":16898,"cross":35459,"percnt":64225,"rmoustache":24179,"supseteqq":29651,"easter":65027,"lbrke":37731,"prsim":37171,"lnap":51747,"rightarrow":7059,"Dstrok":66754,"lfisht":67171,"ngeqslant":25221,"llcorner":1363,"nhpar":41027,"Vbar":67459,"Omacr":42498,"Ncy":42818,"NotVerticalBar":14259,"simdot":1939,"solbar":2643,"bottom":2787,"lneq":2131,"qint":2403,"olcir":43779,"intlarhk":67875,"Lacute":4562,"OpenCurlyDoubleQuote":18899,"YAcy":3538,"nltrie":3779,"Nfr":45396,"lrhard":6531,"SquareUnion":32531,"cwconint":2691,"timesbar":63267,"hksearow":3155,"bigodot":38275,"hardcy":10082,"Bscr":9587,"leftrightharpoons":17651,"triplus":42003,"vert":13969,"upsi":13938,"vltri":24435,"varsupsetneqq":36502,"topfork":43091,"xoplus":16259,"bbrktbrk":12435,"gscr":16211,"lmoust":4003,"gtrarr":19491,"REG":26994,"Ocirc":53554,"ldrushar":16675,"ldquor":21363,"larrfs":21747,"tprime":22147,"LessEqualGreater":3,"Ocy":54882,"hybull":23011,"Not":55747,"uogon":56178,"larrhk":23699,"DoubleRightArrow":24771,"Ofr":57268,"gsim":2867,"daleth":26387,"blank":59011,"lotimes":51171,"Jukcy":59250,"andslope":25475,"lharul":28931,"nvdash":28883,"upharpoonleft":30499,"LeftArrowBar":18035,"larrlp":1459,"rBarr":6483,"gtcc":30883,"Gopf":31732,"DiacriticalGrave":14353,"ropar":62707,"lpar":32673,"vsubnE":33766,"LeftDoubleBracket":6771,"OverBracket":54259,"female":34499,"larrpl":35667,"Element":3875,"cirscir":57219,"thickapprox":12083,"Pscr":36308,"darr":36883,"dash":36979,"race":37301,"lopf":37668,"vsubne":13462,"Pcy":65154,"hamilt":32483,"Assign":39091,"angrtvbd":35379,"Updownarrow":14979,"Yuml":39826,"xdtri":53379,"larrtl":41827,"rangle":28371,"DoubleUpArrow":10499,"Pfr":67508,"uscr":41876,"sdotb":52339,"utdot":68723,"sdote":195,"verbar":13969,"Phi":418,"upuparrows":58403,"congdot":38867,"gnapprox":4483,"spades":44899,"boxDL":3827,"boxDR":5043,"ccedil":22402,"nexist":13171,"rAtail":46403,"NotTildeEqual":1219,"PrecedesTilde":37171,"boxDl":9347,"DifferentialD":18211,"nvrtrie":66342,"boxHD":10035,"boxDr":10451,"curlyeqprec":28275,"lparlt":48835,"straightepsilon":25554,"gtreqless":5187,"boxHU":13267,"lozf":49347,"lbrace":50225,"ntriangleleft":10691,"lbrack":28033,"rang":28371,"raquo":14818,"boxHd":15571,"simgE":15747,"Wcirc":15906,"gtrapprox":8499,"Gammad":52418,"nearrow":4099,"ncedil":53074,"olcross":4435,"softcy":53170,"boxHu":18131,"Uopf":53108,"marker":53875,"simeq":9939,"Qfr":19636,"because":7283,"ddarr":21107,"Psi":21570,"oplus":22259,"smtes":22918,"ldrdhar":10323,"twoheadleftarrow":26899,"NotLessEqual":30451,"rarr":7059,"lrcorner":11219,"simlE":24227,"zopf":56884,"Proportional":7971,"xrArr":25379,"gtrdot":38403,"rarrb":26083,"rarrc":10195,"rarrw":13827,"nwarhk":60883,"topbot":60979,"NotPrecedesSlantEqual":1411,"lthree":42883,"simne":30835,"notindot":60133,"Rcy":32162,"boxUL":32227,"checkmark":10947,"elinters":61315,"boxUR":32931,"boxVH":32979,"boxVL":33635,"ntriangleright":12307,"notniva":23347,"boxVR":34643,"notnivb":24627,"notnivc":24819,"Omega":35970,"Rfr":2995,"topcir":64931,"nearr":4099,"boxUl":37075,"boxUr":37987,"boxVh":38227,"simrarr":27443,"boxVl":38819,"Rho":39058,"gvnE":50134,"boxVr":39555,"uArr":10499,"RightArrowLeftArrow":30979,"Upsi":47202,"Vert":13587,"VerticalLine":13969,"comp":34883,"cong":47779,"GreaterEqual":21923,"utri":51699,"leftrightsquigarrow":42131,"Gscr":68372,"nleftarrow":8707,"NotHumpDownHump":31797,"copf":996,"NotExists":13171,"smeparsl":62419,"rfisht":4947,"theta":44786,"copy":4914,"ratio":46195,"lscr":6964,"rdca":7635,"subrarr":37779,"notinva":15219,"notinvb":38499,"rotimes":38675,"notinvc":38627,"Scy":47106,"nvinfin":39139,"otimesas":5955,"nvsim":47526,"Racute":11138,"uuml":10658,"lowbar":12481,"aring":48706,"acute":12658,"ohbar":49107,"Sfr":49508,"nhArr":49955,"nvDash":15299,"xodot":38275,"Proportion":52243,"Rsh":46627,"Dagger":16435,"preceq":11859,"blk12":51123,"blk14":51459,"boxdL":51507,"filig":51411,"lesssim":11171,"bemptyv":44595,"boxdR":52195,"lsim":11171,"Colon":52243,"rarrap":18723,"period":20561,"LeftTriangleEqual":23155,"blk34":54019,"Longleftarrow":38355,"NotSquareSuperset":3253,"rcub":21025,"succapprox":21603,"gvertneqq":50134,"Tab":55105,"boxdl":55267,"KHcy":21714,"boxhD":55651,"boxdr":55891,"Coproduct":7379,"rmoust":24179,"ltcc":24051,"Darr":24099,"lowast":24867,"Tau":56818,"boxhU":56979,"Lopf":24916,"ReverseUpEquilibrium":18803,"real":2995,"rdquor":26339,"Jcirc":58162,"lcaron":26770,"rarrfs":26803,"boxhd":58259,"odblac":27154,"cemptyv":51219,"circeq":28051,"Tcy":59186,"thicksim":14131,"SquareSubsetEqual":15859,"rarrhk":28691,"lsqb":28033,"boxhu":59939,"rlarr":30979,"Uscr":28580,"rect":28739,"searrow":29795,"qopf":29700,"latail":30787,"nrightarrow":31987,"NotCupCap":15347,"Tfr":61524,"measuredangle":37907,"suplarr":54355,"Scedil":32082,"TildeTilde":12083,"RightAngleBracket":28371,"rharul":34243,"zscr":33572,"seswar":35027,"oline":24003,"rdsh":34451,"rarrlp":35619,"Sub":53827,"Agrave":28002,"Sum":61267,"Sup":2563,"nvlArr":38179,"demptyv":58787,"ominus":30547,"ovbar":65939,"rarrpl":41491,"NestedGreaterGreater":5875,"MinusPlus":36259,"Rang":41443,"sacute":42850,"boxuL":68579,"lrarr":14371,"boxuR":675,"boxvH":947,"nedot":1589,"diams":1891,"Ucy":1762,"boxvL":1843,"frown":2515,"boxvR":3203,"cupbrcap":42627,"lArr":28227,"rarrtl":46019,"LeftTeeVector":34979,"thinsp":46147,"NotSubsetEqual":53715,"eqcolon":22723,"boxul":6003,"RightUpTeeVector":18083,"ltri":46067,"DownArrowBar":64979,"Ufr":6820,"boxur":7187,"boxvh":7491,"boxvl":7843,"Rarr":46723,"gcirc":8850,"rpargt":47427,"boxvr":8883,"DDotrahd":59491,"Zopf":33715,"lesdotor":45715,"searhk":3155,"ddagger":16435,"dwangle":65987,"supsetneq":41075,"alefsym":43395,"doublebarwedge":9155,"Diamond":16963,"equals":881,"cscr":50036,"KJcy":50818,"trade":16387,"leftharpoonup":20307,"infintie":50931,"rbrace":21025,"hearts":54835,"rbrack":47409,"uparrow":5539,"circledast":27315,"Vcy":22546,"Vee":20659,"becaus":7283,"CapitalDifferentialD":46307,"abreve":56786,"Fouriertrf":48531,"tcedil":56946,"cirfnint":55699,"YIcy":57186,"circledcirc":62371,"atilde":30258,"Vfr":25844,"bigstar":2083,"LeftRightVector":23491,"diam":16963,"UnderBracket":60931,"rightleftharpoons":16067,"rtrie":3619,"rtrif":29843,"Copf":59379,"primes":58307,"NotEqual":46675,"lvnE":23062,"omacr":30754,"planck":6227,"FilledSmallSquare":7107,"sfrown":2515,"digamma":6098,"UpArrowDownArrow":26579,"ulcorner":21315,"Lscr":23251,"iecy":63730,"hopf":64004,"rthree":56131,"MediumSpace":55843,"mlcp":64643,"Uuml":31330,"UpDownArrow":99,"natural":7763,"mldr":33027,"permil":66947,"qscr":66884,"rtriltri":59331,"csub":66995,"NotGreaterGreater":5877,"thkap":12083,"veeeq":42179,"csup":68083,"Wfr":42308,"nsimeq":1219,"imped":43442,"subdot":3363,"varsubsetneqq":33766,"awint":45251,"plankv":6227,"ocirc":45554,"NotSquareSubsetEqual":48915,"hookleftarrow":23699,"djcy":9026,"nrarrc":10197,"napE":10581,"RightCeiling":7715,"NotGreaterFullEqual":3045,"lsaquo":12387,"gtreqqless":27027,"Verbar":13587,"angle":12899,"sqsupseteq":6179,"nrarrw":13829,"nang":12902,"laemptyv":9843,"plussim":42451,"uHar":14451,"planckh":43139,"coloneq":39091,"jukcy":50786,"brvbar":16930,"ltimes":17155,"Ccedil":17298,"Qopf":16531,"Emacr":51970,"Kappa":52386,"iiint":16163,"wedbar":20115,"LeftUpDownVector":66099,"ctdot":54163,"rhov":20994,"UnderBrace":14035,"Xfr":54404,"Zscr":21508,"curlyvee":17939,"vopf":22772,"RightFloor":4595,"gtquest":49251,"Precedes":31635,"angrt":57539,"smashp":26291,"timesb":26723,"timesd":26947,"uuarr":58403,"angst":48578,"bumpE":58547,"NotPrecedes":51,"Ncedil":27714,"cacute":28146,"supplus":52291,"lltri":59827,"ncap":28643,"straightphi":3458,"infin":60611,"cups":29558,"supdot":31075,"bumpe":9203,"DiacriticalTilde":12274,"rcaron":31906,"udblac":32306,"sqcups":32582,"Ecirc":62626,"ring":32898,"Ycy":63010,"UnionPlus":29123,"puncsp":35923,"scnsim":36211,"ratail":36931,"Yfr":64788,"nacute":38594,"supseteq":25587,"ThinSpace":46147,"circleddash":22019,"VerticalBar":26483,"zwnj":39507,"nbsp":35426,"phmmat":25715,"nabla":31203,"mcomma":41635,"Cscr":40852,"RuleDelayed":28467,"biguplus":24483,"bNot":42259,"rlhar":16067,"wcirc":1186,"starf":2083,"nearhk":44947,"hscr":45060,"veebar":46355,"yacute":36050,"DownLeftRightVector":59059,"rceil":7715,"circlearrowright":45459,"angzarr":66291,"Zcy":10114,"Ubrcy":10546,"plustwo":68291,"LongLeftRightArrow":25427,"preccurlyeq":20019,"quot":36865,"grave":14353,"equest":50531,"UpArrowBar":53971,"Zfr":14547,"cupcap":51555,"urcorner":28323,"lrhar":17651,"DoubleLeftRightArrow":2035,"LongLeftArrow":36723,"AElig":20898,"ncup":54579,"varpropto":7971,"lHar":55171,"Aogon":22066,"odash":22019,"Breve":9394,"DoubleDownArrow":37027,"Hopf":49907,"Idot":56626,"ShortDownArrow":36883,"swArr":24339,"blacksquare":27667,"omega":25106,"models":58083,"Tilde":14131,"rhard":25299,"LessGreater":15619,"PrecedesEqual":11859,"triangleleft":46067,"Qscr":58948,"rharu":27187,"mopf":59716,"gbreve":60306,"setminus":14499,"LessFullEqual":17603,"ReverseEquilibrium":17651,"nsime":1219,"NegativeMediumSpace":2323,"vscr":62564,"sstarf":56019,"eplus":34835,"NotLess":24531,"Lcaron":64066,"Odblac":64338,"target":64387,"downarrow":36883,"ApplyFunction":28979,"barvee":64595,"ltquest":25987,"nrArr":18259,"VerticalTilde":9987]`; 14 | package __gshared immutable static ubyte[4298] bytes_ = [226,139,154,226,138,128,226,134,149,226,165,164,226,169,166,195,141,226,128,138,226,136,169,239,184,128,206,166,206,191,226,169,189,226,169,139,240,157,147,142,197,164,226,149,152,226,167,132,226,136,179,36,226,170,187,61,226,131,165,226,149,170,240,157,149,148,226,138,137,226,135,155,196,166,197,181,226,137,132,226,164,141,226,128,181,226,140,158,226,139,160,226,134,171,226,137,191,204,184,226,137,144,204,184,226,169,185,226,159,137,208,163,226,136,165,226,149,161,226,153,166,226,169,170,226,137,164,226,135,148,226,152,133,226,170,135,195,166,208,182,226,168,173,197,169,226,128,139,195,171,226,168,140,240,157,146,185,226,140,162,226,139,145,208,183,226,140,191,226,136,178,226,132,149,226,138,165,195,161,226,137,179,226,137,142,208,166,226,132,156,226,137,167,204,184,207,131,226,164,165,226,149,158,226,138,144,204,184,195,132,226,170,189,226,136,171,207,149,226,128,153,208,175,226,136,190,226,138,181,226,139,136,240,157,148,138,226,139,172,226,149,151,226,136,136,209,149,226,137,169,226,142,176,226,139,130,226,134,151,208,137,240,157,146,170,226,136,131,226,166,154,226,138,170,226,132,157,226,166,187,226,170,138,195,185,196,185,226,140,139,240,157,148,169,195,136,226,170,188,226,128,147,102,106,226,139,161,194,169,226,165,189,226,137,189,226,149,148,226,170,165,226,168,162,226,139,155,226,138,147,239,184,128,204,145,226,137,130,226,169,183,226,134,182,195,158,226,134,145,194,171,195,149,226,170,186,206,181,197,138,226,138,159,240,157,149,156,226,137,171,204,184,226,168,182,226,148,152,226,136,184,207,157,226,135,181,226,138,146,226,132,143,226,137,150,226,169,138,226,171,133,195,150,197,129,226,164,143,226,165,173,226,132,144,226,170,179,226,137,175,226,170,164,226,159,166,240,157,148,152,197,131,226,139,159,240,157,147,129,195,170,226,134,146,226,151,188,194,183,226,148,148,226,139,146,226,136,181,226,132,169,226,136,144,240,157,149,141,226,148,188,208,155,240,157,148,183,226,164,183,209,145,226,140,137,226,153,174,194,163,226,148,164,194,162,226,170,142,226,136,157,195,147,209,155,226,138,190,226,137,140,226,136,154,240,157,146,178,226,138,130,196,133,197,189,226,165,190,226,132,152,226,170,134,226,137,147,240,157,148,184,226,171,131,226,134,154,226,168,184,226,159,167,196,157,226,148,156,226,139,141,226,153,163,209,146,226,170,144,226,129,162,226,140,134,226,137,143,204,184,206,179,197,137,226,149,150,203,152,226,168,174,226,170,136,240,157,148,160,226,132,172,226,166,142,226,164,144,240,157,149,164,226,138,191,226,166,180,226,135,137,226,137,131,226,137,128,226,149,166,209,138,208,151,226,138,151,226,164,179,204,184,226,131,155,226,165,167,195,183,226,169,186,226,149,147,226,135,145,208,142,226,169,176,204,184,195,188,226,139,170,240,157,147,137,226,138,134,226,166,145,226,133,136,226,156,147,226,137,185,226,134,165,226,159,188,197,148,226,137,178,226,140,159,226,156,182,226,170,191,226,138,131,226,131,146,194,168,226,134,178,203,135,240,157,148,143,207,135,226,136,133,226,171,151,226,134,186,226,137,168,226,170,175,209,134,226,128,135,226,135,157,226,157,178,226,137,136,226,135,135,208,136,240,157,148,174,203,156,226,139,171,197,154,226,128,185,226,142,182,95,240,157,149,128,226,166,144,226,139,168,194,180,226,130,172,195,151,209,143,226,128,132,226,138,129,226,136,160,226,131,146,226,135,191,226,128,133,226,137,130,204,184,226,136,132,226,165,174,226,149,169,226,150,191,209,153,206,148,208,139,226,138,138,239,184,128,195,152,226,128,150,226,137,187,226,165,151,208,131,240,157,146,165,226,134,157,204,184,195,130,207,133,124,226,136,166,226,143,159,226,165,159,226,136,188,226,136,128,194,175,226,136,164,226,140,133,96,226,135,134,203,153,226,165,163,226,136,150,226,132,168,207,136,226,171,135,197,128,226,139,163,195,154,195,191,194,187,195,187,226,138,132,226,135,131,226,135,149,226,139,173,240,157,149,151,206,158,226,151,139,226,136,137,194,184,226,138,173,226,137,173,194,191,197,166,226,134,166,226,151,172,94,226,149,164,226,137,182,196,161,226,170,139,226,170,160,208,178,194,164,226,138,145,197,180,226,135,141,226,167,143,204,184,226,135,140,226,136,168,226,136,173,226,132,138,226,168,129,195,160,226,138,141,226,132,162,226,128,161,226,128,162,226,132,154,226,169,184,226,132,173,226,165,139,226,168,188,226,166,167,195,144,226,134,189,195,129,194,166,226,139,132,226,128,149,240,157,148,165,206,163,226,139,137,226,138,133,226,170,183,195,135,226,137,181,226,132,155,226,164,150,226,170,129,226,168,187,194,161,226,137,166,226,135,139,208,167,226,134,153,38,226,165,148,226,167,144,226,169,175,226,139,142,226,167,141,226,135,164,226,165,156,226,149,167,196,141,226,133,134,226,135,143,226,171,176,226,139,166,194,181,226,136,139,226,165,150,226,166,168,226,137,156,226,164,159,226,166,169,226,165,181,206,167,226,165,175,226,129,151,226,128,156,226,165,158,226,170,175,204,184,226,166,170,206,153,240,157,149,159,195,157,226,128,186,226,137,135,226,166,171,226,159,182,226,151,175,226,165,184,226,166,172,226,129,160,240,157,148,148,226,159,170,226,134,148,226,166,173,196,143,226,137,184,226,138,153,226,139,148,226,137,188,226,166,174,226,169,159,226,136,180,226,168,130,226,166,175,226,134,188,226,165,149,240,157,148,179,226,166,146,226,132,180,46,197,185,226,166,165,226,139,129,226,170,185,226,136,189,226,165,157,226,137,170,195,134,240,157,149,144,207,177,125,208,188,196,155,226,135,138,197,187,226,138,162,226,170,176,204,184,226,140,156,226,128,158,226,157,179,226,137,172,240,157,146,181,206,168,226,170,184,240,157,148,187,208,165,226,164,157,196,162,226,171,168,226,169,150,226,137,165,226,168,141,226,138,157,196,132,226,150,185,226,128,180,196,150,209,147,226,138,149,226,164,133,226,151,138,195,167,226,153,173,203,157,196,156,208,146,226,138,130,226,131,146,226,132,176,226,137,149,240,157,149,167,206,147,226,135,130,226,170,172,239,184,128,226,129,131,226,137,168,239,184,128,226,138,180,226,151,130,226,132,146,226,166,191,226,136,140,226,166,150,226,134,164,226,165,142,226,139,138,240,157,147,140,226,167,182,226,134,169,226,134,150,226,164,168,226,132,140,240,157,149,146,226,170,149,226,128,190,226,170,166,226,134,161,196,171,226,142,177,226,170,159,240,157,148,170,226,135,153,226,171,140,226,138,178,226,168,132,226,137,174,226,136,174,226,139,190,240,157,146,183,208,180,226,135,146,226,139,189,226,136,151,240,157,149,131,226,140,173,208,168,226,137,177,207,137,226,128,142,196,165,226,169,190,204,184,226,135,129,194,176,226,159,185,226,159,183,226,169,152,196,182,207,181,226,138,135,226,139,167,209,135,226,132,179,226,134,176,197,175,240,157,148,153,226,165,138,197,157,226,169,187,226,169,137,226,135,165,226,150,132,196,187,226,171,139,208,156,226,168,179,226,128,157,226,132,184,226,171,166,226,136,163,226,132,167,226,135,133,209,128,240,157,149,154,226,138,160,196,190,226,164,158,226,131,156,226,134,158,226,168,176,194,174,226,170,140,194,185,226,147,136,197,145,226,135,128,194,178,226,138,175,226,138,155,194,179,226,129,143,226,165,178,240,157,146,191,226,171,130,240,157,149,139,226,150,170,197,133,240,157,148,161,226,136,187,226,171,153,226,132,145,226,166,143,195,128,91,226,137,151,226,137,162,196,135,226,128,177,226,135,144,226,139,158,226,140,157,226,159,169,226,129,129,226,167,180,209,133,197,136,240,157,146,176,226,169,131,226,134,170,226,150,173,226,164,166,226,168,134,226,138,172,226,165,170,226,129,161,226,137,139,226,159,191,226,138,142,226,136,152,226,128,165,226,139,154,239,184,128,226,134,183,226,136,130,207,176,240,157,148,144,226,136,170,239,184,128,226,171,134,240,157,149,162,195,169,226,134,152,226,150,184,208,148,207,145,240,157,148,175,226,138,168,226,166,141,226,128,178,226,135,150,226,169,179,195,163,196,145,208,184,208,169,240,157,147,135,226,137,176,226,134,191,226,138,150,226,171,134,204,184,226,169,189,204,184,197,141,226,164,153,226,137,134,226,170,167,226,137,141,226,135,132,226,134,181,226,170,190,226,139,150,196,137,226,136,135,197,150,226,153,170,195,156,209,136,226,137,153,226,136,186,199,181,208,174,226,171,149,206,185,226,137,186,226,170,132,240,157,148,190,226,137,142,204,184,208,172,197,153,226,143,156,226,134,155,226,159,168,197,158,226,135,154,208,160,206,146,226,149,157,206,149,197,177,226,137,137,207,129,196,130,195,143,226,132,139,226,138,148,226,138,148,239,184,128,40,197,161,226,136,148,240,157,149,170,197,183,197,162,203,154,226,149,154,226,149,172,226,128,166,197,188,226,140,138,207,130,195,173,226,164,189,239,172,131,240,157,148,135,226,129,163,226,137,138,226,137,183,226,171,147,240,157,147,143,226,149,163,197,165,226,132,164,226,171,139,239,184,128,226,138,143,226,128,141,240,157,149,149,240,157,148,166,196,167,194,189,226,170,173,239,184,128,226,165,172,226,132,133,226,133,147,196,151,194,188,226,134,179,226,153,128,226,165,146,226,133,149,226,149,160,226,133,153,226,170,182,226,133,135,226,169,177,226,136,129,226,169,135,226,165,154,226,164,169,196,170,226,132,175,226,139,185,226,133,155,195,131,226,170,154,226,159,186,226,166,157,194,160,226,156,151,240,157,149,134,226,168,150,226,134,172,226,164,185,206,155,195,159,226,139,128,226,135,152,226,170,153,226,128,136,206,169,226,133,148,195,189,226,128,131,226,170,180,196,164,226,139,169,226,136,147,240,157,146,171,195,142,226,143,158,226,133,150,226,171,140,239,184,128,226,140,144,196,186,226,132,150,226,159,181,208,152,240,157,148,180,34,226,134,147,226,164,154,226,128,144,226,135,147,226,149,156,226,170,128,226,137,190,197,174,208,189,43,226,136,189,204,177,197,156,226,139,131,226,138,152,226,150,179,226,137,141,226,131,146,10,240,157,149,157,226,166,139,226,165,185,226,167,133,195,176,226,136,161,194,190,226,149,153,226,133,151,226,139,155,239,184,128,226,164,130,226,149,171,226,168,128,197,130,226,159,184,226,139,151,226,138,179,226,139,183,226,133,156,197,132,226,139,182,226,168,181,196,158,240,157,147,130,226,149,162,226,169,173,204,184,226,128,143,240,157,149,142,206,161,226,137,148,226,167,158,197,171,226,165,153,195,174,226,165,168,209,142,226,139,179,226,138,164,195,179,226,128,140,226,149,159,208,143,226,139,181,226,137,161,226,131,165,226,133,152,197,184,206,165,240,157,146,179,197,190,226,151,184,226,139,147,226,170,162,240,157,148,185,226,134,144,226,136,176,62,196,138,196,184,226,168,170,226,167,144,204,184,226,171,136,226,169,181,226,138,174,39,226,137,145,240,157,148,171,209,150,226,168,148,240,157,146,158,33,226,139,143,226,153,175,226,171,178,226,138,139,239,184,128,240,157,149,165,226,164,188,207,182,226,136,167,226,133,154,209,141,226,159,171,226,165,133,226,133,157,226,143,157,226,168,169,226,169,191,226,139,180,226,138,171,226,134,162,240,157,147,138,92,226,128,179,226,168,185,226,138,176,197,149,226,134,173,226,137,154,206,150,226,171,173,240,157,148,154,226,135,151,196,168,226,168,166,197,140,226,169,180,226,164,155,226,169,136,195,164,226,171,167,209,152,196,136,208,157,197,155,226,139,139,240,157,149,129,226,170,181,226,169,128,226,171,154,226,132,142,209,129,226,165,152,226,137,166,204,184,226,165,160,226,132,181,198,181,240,157,146,166,226,166,183,195,140,194,167,226,136,190,204,179,226,133,158,226,166,190,239,172,128,226,171,133,204,184,196,147,239,172,132,197,182,240,157,148,162,226,170,130,195,186,226,150,161,58,226,165,147,206,186,226,137,165,226,131,146,226,165,155,226,171,175,226,166,140,226,166,176,240,157,149,152,226,139,188,197,167,206,184,226,171,179,206,178,226,153,160,226,164,164,195,175,196,175,240,157,146,189,195,162,226,128,160,226,134,190,226,168,145,226,170,150,226,139,174,240,157,148,145,226,134,187,226,132,182,195,180,209,159,226,168,175,226,138,163,226,170,131,208,173,240,157,148,176,62,226,131,146,195,145,240,157,146,174,226,134,163,226,151,131,208,185,226,128,137,226,136,182,226,134,174,60,226,133,133,226,138,187,226,164,156,196,177,196,178,240,157,149,160,226,136,191,226,134,177,226,137,160,226,134,160,226,136,143,226,157,152,226,165,161,226,138,184,226,166,179,226,171,169,226,167,156,208,161,240,157,147,133,207,146,197,186,206,188,195,146,196,179,226,134,167,93,226,166,148,226,171,152,226,136,188,226,131,146,197,170,64,226,169,149,240,157,148,136,226,137,133,240,157,148,188,194,172,226,139,135,226,168,165,206,189,226,171,164,194,173,240,157,148,167,226,140,141,226,136,130,204,184,226,167,165,197,172,226,150,136,226,169,141,208,176,226,132,177,195,133,240,157,149,168,208,134,195,165,226,140,146,226,150,171,226,166,147,207,128,226,139,162,195,172,226,136,172,240,157,147,141,226,166,181,226,137,164,226,131,146,226,169,188,226,170,168,226,167,171,226,166,188,240,157,149,147,240,157,148,150,194,177,226,128,130,226,132,147,226,136,146,196,181,196,139,208,153,240,157,148,181,226,132,141,226,135,142,197,168,240,157,146,184,208,190,226,137,169,239,184,128,123,226,171,132,240,157,149,132,226,159,136,226,166,185,226,165,176,196,183,226,137,159,226,138,169,60,226,131,146,226,150,177,226,168,147,209,148,208,140,240,157,146,169,41,226,167,157,195,153,226,151,187,240,157,148,158,226,150,146,226,168,180,226,166,178,206,182,226,167,163,197,139,196,188,239,172,129,226,150,145,226,149,149,226,169,134,226,139,187,226,128,152,226,150,181,226,170,137,226,138,143,204,184,226,143,162,226,169,151,196,146,226,167,137,209,137,240,157,149,155,226,164,132,226,149,146,226,136,183,226,171,128,226,138,161,206,154,207,156,226,168,186,226,165,165,207,132,226,166,156,44,226,169,133,226,136,162,206,152,226,170,151,195,190,240,157,148,141,240,157,147,128,226,171,148,226,132,151,197,134,240,157,149,140,209,140,208,144,240,157,148,172,196,174,226,132,158,226,150,189,226,168,149,226,167,131,209,132,195,148,226,170,170,226,139,185,204,184,226,138,136,240,157,146,177,226,139,144,226,150,174,226,165,180,226,164,146,226,150,147,226,153,130,226,140,140,226,139,175,226,171,150,226,142,180,226,128,154,226,165,187,240,157,148,155,226,167,129,240,157,146,156,226,169,130,226,139,149,226,150,180,240,157,149,163,226,170,169,226,153,165,208,158,226,134,159,226,165,177,226,164,131,226,138,182,9,226,139,133,226,165,162,226,140,149,226,148,144,195,177,47,226,171,145,195,178,209,130,206,177,240,157,147,136,226,137,170,204,184,226,149,165,226,168,144,226,171,172,226,156,160,226,129,159,226,148,140,226,149,144,197,151,226,139,134,240,157,148,132,226,139,140,197,179,226,170,158,226,137,129,226,151,185,240,157,148,163,226,171,129,203,134,197,159,226,164,142,226,170,157,196,176,209,156,226,169,144,226,165,143,196,131,206,164,200,183,240,157,149,171,197,163,226,149,168,35,226,149,145,226,159,172,226,148,128,208,135,226,167,130,240,157,148,146,196,191,226,165,166,197,146,226,170,152,226,138,158,226,136,159,226,171,189,226,131,165,206,183,226,166,133,208,164,240,157,149,150,240,157,148,177,208,170,226,169,178,208,186,226,150,190,226,138,167,206,190,196,180,240,157,146,187,226,148,172,226,132,153,226,165,169,226,135,136,226,137,180,226,164,182,226,170,174,197,147,206,187,226,164,170,196,129,226,138,186,226,166,177,195,155,226,169,156,208,138,240,157,146,172,226,144,163,226,165,144,226,170,161,204,184,208,162,194,165,208,132,239,172,130,226,167,142,226,132,130,196,140,209,139,226,164,145,226,169,132,226,140,143,196,153,226,167,128,240,157,149,158,226,139,153,226,151,186,194,182,208,149,226,148,180,226,148,130,240,157,148,137,196,142,226,139,181,204,184,240,157,148,168,195,182,196,159,240,157,147,131,226,139,178,226,137,146,226,169,154,206,159,195,184,226,136,158,240,157,149,143,208,177,226,138,185,196,154,226,168,183,226,164,163,226,142,181,226,140,182,226,164,167,203,155,226,170,133,240,157,146,180,226,138,183,226,136,145,226,143,167,226,140,163,226,139,153,204,184,206,151,240,157,148,151,195,168,195,139,208,154,240,157,148,182,240,157,146,159,226,140,174,226,166,164,240,157,149,166,226,152,142,209,151,226,159,173,226,168,163,226,135,189,208,191,226,138,180,226,131,146,226,128,148,226,138,154,226,167,164,226,137,171,226,131,146,240,157,147,139,195,138,226,169,147,226,166,134,206,145,240,157,148,159,59,196,169,226,165,191,240,157,146,182,208,171,226,165,137,240,157,149,130,197,178,209,154,226,139,177,226,168,177,240,157,148,142,226,169,157,226,166,149,226,152,134,195,181,226,136,175,195,137,208,145,240,157,148,173,208,181,194,170,226,140,142,194,186,226,136,177,226,129,132,208,179,240,157,149,153,196,189,226,164,184,198,146,226,164,140,37,226,168,146,226,165,179,197,144,42,226,140,150,226,139,152,240,157,146,190,226,164,181,226,138,189,226,171,155,240,157,149,138,208,150,240,157,148,156,207,134,226,150,128,226,171,177,226,164,147,226,169,174,226,169,155,196,134,208,159,226,170,147,197,135,240,157,146,175,196,128,226,169,140,209,131,226,129,159,226,128,138,226,165,136,208,133,63,226,137,139,204,184,226,170,171,226,168,191,226,139,186,226,139,152,204,184,226,140,189,226,166,166,240,157,148,133,226,165,145,240,157,149,161,226,135,190,206,156,226,141,188,226,138,181,226,131,146,209,158,240,157,148,164,196,152,226,170,148,226,140,136,226,140,147,226,165,171,196,144,226,137,170,226,131,146,240,157,147,134,226,128,176,226,171,143,226,171,174,207,150,226,165,182,226,165,188,226,164,160,226,170,162,204,184,206,157,208,129,226,170,145,226,171,171,240,157,148,147,206,180,240,157,148,189,226,168,164,197,152,208,147,240,157,148,178,196,160,226,168,151,226,170,141,197,176,197,173,226,169,148,226,171,144,226,170,143,226,132,183,208,187,206,160,226,168,167,208,130,240,157,146,162,226,170,146,240,157,149,169,197,160,226,149,155,226,171,146,226,166,182,226,139,176]; 15 | package __gshared immutable static uint[const(char)[]] index_; 16 | 17 | 18 | package auto codeOffset(uint indexValue) { 19 | return indexValue >> 4; 20 | } 21 | 22 | package auto codeLength(uint indexValue) { 23 | return indexValue & 15; 24 | } 25 | 26 | auto getNamedEntityUTF8(const(char)[] name) { 27 | if (name.length) { 28 | if (__ctfe) { 29 | immutable index = mixin(EntityIndexDef); 30 | if (auto pindex = name in index) { 31 | auto offset = codeOffset(*pindex); 32 | auto length = codeLength(*pindex); 33 | return cast(const(char)[])bytes_[offset..offset + length]; 34 | } 35 | } else { 36 | if (auto pindex = name in index_) { 37 | auto offset = codeOffset(*pindex); 38 | auto length = codeLength(*pindex); 39 | return cast(const(char)[])bytes_[offset..offset + length]; 40 | } 41 | } 42 | } 43 | return null; 44 | } 45 | 46 | auto getEntityUTF8(const(char)[] name) { 47 | import std.conv; 48 | 49 | if (name.length > 1) { 50 | if (name[0] == '#') { 51 | int code = 0; 52 | if ((name[1] == 'x') || (name[1] == 'X')) { 53 | name = name[2..min(2+4, $)]; 54 | code = parse!int(name, 16); 55 | } else { 56 | name = name[2..min(1+4, $)]; 57 | code = parse!int(name); 58 | } 59 | 60 | return decodeCodePoint(code); 61 | } 62 | } 63 | return getNamedEntityUTF8(name); 64 | } 65 | 66 | package auto decodeCodePoint(int code) { 67 | import std.range; 68 | 69 | static char[4] buf; 70 | dchar[1] input = [code]; 71 | return buf[0 .. $ - input[ ].byChar().copy(buf[ ].byChar()).length]; 72 | } 73 | 74 | shared static this() { 75 | index_ = mixin(EntityIndexDef); 76 | } -------------------------------------------------------------------------------- /src/html/dom.d: -------------------------------------------------------------------------------- 1 | module html.dom; 2 | 3 | 4 | import std.algorithm; 5 | import std.array; 6 | import std.ascii; 7 | import std.conv; 8 | import std.experimental.allocator; 9 | import std.range; 10 | import std.string; 11 | import std.typecons; 12 | 13 | import html.parser; 14 | import html.utils; 15 | 16 | 17 | alias HTMLString = const(char)[]; 18 | static if(__VERSION__ >= 2079){ 19 | alias IAllocator = RCIAllocator; 20 | } 21 | 22 | enum DOMCreateOptions { 23 | None = 0, 24 | DecodeEntities = 1 << 0, 25 | 26 | ValidateClosed = 1 << 10, 27 | ValidateSelfClosing = 1 << 11, 28 | ValidateDuplicateAttr = 1 << 12, 29 | ValidateBasic = ValidateClosed | ValidateSelfClosing | ValidateDuplicateAttr, 30 | ValidateAll = ValidateBasic, 31 | 32 | Default = DecodeEntities, 33 | } 34 | 35 | 36 | enum ValidationError : size_t { 37 | None, 38 | MismatchingClose = 1, 39 | MissingClose, 40 | StrayClose, 41 | SelfClosingNonVoidElement, 42 | DuplicateAttr, 43 | } 44 | 45 | 46 | alias ValidationErrorCallable = void delegate(ValidationError, HTMLString, HTMLString); 47 | 48 | 49 | alias onlyElements = a => a.isElementNode; 50 | 51 | 52 | private struct ChildrenForward(NodeType, alias Condition = null) { 53 | this(NodeType first) { 54 | curr_ = cast(Node)first; 55 | static if (!is(typeof(Condition) == typeof(null))) { 56 | while (curr_ && !Condition(curr_)) 57 | curr_ = curr_.next_; 58 | } 59 | } 60 | 61 | bool empty() const { 62 | return (curr_ is null); 63 | } 64 | 65 | NodeType front() const { 66 | return cast(NodeType)curr_; 67 | } 68 | 69 | void popFront() { 70 | curr_ = curr_.next_; 71 | 72 | static if (!is(typeof(Condition) == typeof(null))) { 73 | while (curr_) { 74 | if (Condition(curr_)) 75 | break; 76 | curr_ = curr_.next_; 77 | } 78 | } 79 | } 80 | 81 | private Node curr_; 82 | } 83 | 84 | 85 | private struct AncestorsForward(NodeType, alias Condition = null) { 86 | this(NodeType first) { 87 | curr_ = cast(Node)first; 88 | static if (!is(typeof(Condition) == typeof(null))) { 89 | while (curr_ && !Condition(curr_)) 90 | curr_ = curr_.parent_; 91 | } 92 | } 93 | 94 | bool empty() const { 95 | return (curr_ is null); 96 | } 97 | 98 | NodeType front() const { 99 | return cast(NodeType)curr_; 100 | } 101 | 102 | void popFront() { 103 | curr_ = curr_.parent_; 104 | 105 | static if (!is(typeof(Condition) == typeof(null))) { 106 | while (curr_) { 107 | if (Condition(curr_)) 108 | break; 109 | curr_ = curr_.parent_; 110 | } 111 | } 112 | } 113 | 114 | private Node curr_; 115 | } 116 | 117 | 118 | private struct DescendantsForward(NodeType, alias Condition = null) { 119 | this(NodeType top) { 120 | if (top is null) 121 | return; 122 | curr_ = cast(Node)top.firstChild_; // top itself is excluded 123 | top_ = cast(Node)top; 124 | static if (!is(typeof(Condition) == typeof(null))) { 125 | if (!Condition(curr_)) 126 | popFront; 127 | } 128 | } 129 | 130 | bool empty() const { 131 | return (curr_ is null); 132 | } 133 | 134 | NodeType front() const { 135 | return cast(NodeType)curr_; 136 | } 137 | 138 | void popFront() { 139 | while (curr_) { 140 | if (curr_.firstChild_) { 141 | curr_ = curr_.firstChild_; 142 | } else if (curr_ !is top_) { 143 | auto next = curr_.next_; 144 | if (!next) { 145 | Node parent = curr_.parent_; 146 | while (parent) { 147 | if (parent !is top_) { 148 | if (parent.next_) { 149 | next = parent.next_; 150 | break; 151 | } 152 | parent = parent.parent_; 153 | } else { 154 | next = null; 155 | break; 156 | } 157 | } 158 | } 159 | 160 | curr_ = next; 161 | if (!curr_) 162 | break; 163 | } else { 164 | curr_ = null; 165 | break; 166 | } 167 | 168 | static if (is(typeof(Condition) == typeof(null))) { 169 | break; 170 | } else { 171 | if (Condition(curr_)) 172 | break; 173 | } 174 | } 175 | } 176 | 177 | private Node curr_; 178 | private Node top_; 179 | } 180 | 181 | unittest { 182 | const doc = createDocument(`