diff --git a/pkgs/html/CHANGELOG.md b/pkgs/html/CHANGELOG.md
index aa68aed2d5..c0e48769e5 100644
--- a/pkgs/html/CHANGELOG.md
+++ b/pkgs/html/CHANGELOG.md
@@ -1,5 +1,7 @@
-## 0.15.6-wip
+## 0.15.6
+- Performance improvements.
+- No longer generate any error spans if generateSpans is false.
- Fixed a TypeError in nth-child with non numeric value (e.g. `nth-child(even)`)
## 0.15.5+1
diff --git a/pkgs/html/lib/parser.dart b/pkgs/html/lib/parser.dart
index 0e89e663a6..65cc263c1b 100644
--- a/pkgs/html/lib/parser.dart
+++ b/pkgs/html/lib/parser.dart
@@ -2026,7 +2026,7 @@ class InBodyPhase extends Phase {
}
void endTagHeading(EndTagToken token) {
- for (var item in headingElements) {
+ for (var item in headingElementsList) {
if (tree.elementInScope(item)) {
tree.generateImpliedEndTags();
break;
@@ -2036,7 +2036,7 @@ class InBodyPhase extends Phase {
parser.parseError(token.span, 'end-tag-too-early', {'name': token.name});
}
- for (var item in headingElements) {
+ for (var item in headingElementsList) {
if (tree.elementInScope(item)) {
var node = tree.openElements.removeLast();
while (!headingElements.contains(node.localName)) {
@@ -3972,6 +3972,9 @@ class ParseError implements SourceSpanException {
@override
String toString({dynamic color}) {
+ if (span == null) {
+ return message;
+ }
final res = span!.message(message, color: color);
return span!.sourceUrl == null ? 'ParserError on $res' : 'On $res';
}
diff --git a/pkgs/html/lib/src/constants.dart b/pkgs/html/lib/src/constants.dart
index e70b1e2634..34418199a6 100644
--- a/pkgs/html/lib/src/constants.dart
+++ b/pkgs/html/lib/src/constants.dart
@@ -258,7 +258,7 @@ class Namespaces {
}
}
-const List<(String, String)> scopingElements = [
+const scopingElements = {
(Namespaces.html, 'applet'),
(Namespaces.html, 'caption'),
(Namespaces.html, 'html'),
@@ -276,9 +276,9 @@ const List<(String, String)> scopingElements = [
(Namespaces.svg, 'foreignObject'),
(Namespaces.svg, 'desc'),
(Namespaces.svg, 'title')
-];
+};
-const formattingElements = [
+const formattingElements = {
(Namespaces.html, 'a'),
(Namespaces.html, 'b'),
(Namespaces.html, 'big'),
@@ -293,9 +293,9 @@ const formattingElements = [
(Namespaces.html, 'strong'),
(Namespaces.html, 'tt'),
(Namespaces.html, '')
-];
+};
-const specialElements = [
+const specialElements = {
(Namespaces.html, 'address'),
(Namespaces.html, 'applet'),
(Namespaces.html, 'area'),
@@ -376,27 +376,86 @@ const specialElements = [
(Namespaces.html, 'wbr'),
(Namespaces.html, 'xmp'),
(Namespaces.svg, 'foreignObject')
-];
+};
-const htmlIntegrationPointElements = [
+const htmlIntegrationPointElements = {
(Namespaces.mathml, 'annotaion-xml'),
(Namespaces.svg, 'foreignObject'),
(Namespaces.svg, 'desc'),
(Namespaces.svg, 'title')
-];
+};
-const mathmlTextIntegrationPointElements = [
+const mathmlTextIntegrationPointElements = {
(Namespaces.mathml, 'mi'),
(Namespaces.mathml, 'mo'),
(Namespaces.mathml, 'mn'),
(Namespaces.mathml, 'ms'),
(Namespaces.mathml, 'mtext')
-];
+};
+
+abstract final class Charcode {
+ static const int nul = 0x00;
+
+ /// '\t'
+ static const int tab = 0x09;
+
+ /// '\n'
+ static const int lineFeed = 0x0A;
+ static const int formFeed = 0x0C;
+
+ /// '\r'
+ static const int carriageReturn = 0x0D;
+
+ /// ' '
+ static const int space = 0x20;
+
+ /// '"'
+ static const int doubleQuote = 0x22;
+
+ /// '&'
+ static const int ampersand = 0x26;
+
+ /// "'"
+ static const int singleQuote = 0x27;
+
+ /// '-'
+ static const int hyphen = 0x2D;
-const spaceCharacters = ' \n\r\t\u000C';
+ /// 0
+ static const int zero = 0x30;
-const int newLine = 10;
-const int returnCode = 13;
+ /// '<'
+ static const int lessThan = 0x3C;
+
+ /// '='
+ static const int equals = 0x3D;
+
+ /// '>'
+ static const int greaterThan = 0x3E;
+
+ /// A
+ static const int upperA = 0x41;
+
+ /// Z
+ static const int upperZ = 0x5A;
+
+ /// '`'
+ static const int graveAccent = 0x60;
+
+ /// a
+ static const int lowerA = 0x61;
+
+ /// z
+ static const int lowerZ = 0x7A;
+}
+
+const spaceCharacters = {
+ Charcode.space,
+ Charcode.lineFeed,
+ Charcode.carriageReturn,
+ Charcode.tab,
+ Charcode.formFeed
+};
bool isWhitespace(String? char) {
if (char == null) return false;
@@ -405,32 +464,17 @@ bool isWhitespace(String? char) {
bool isWhitespaceCC(int charCode) {
switch (charCode) {
- case 9: // '\t'
- case newLine: // '\n'
- case 12: // '\f'
- case returnCode: // '\r'
- case 32: // ' '
+ case Charcode.tab:
+ case Charcode.lineFeed:
+ case Charcode.formFeed:
+ case Charcode.carriageReturn:
+ case Charcode.space:
return true;
}
return false;
}
-const List tableInsertModeElements = [
- 'table',
- 'tbody',
- 'tfoot',
- 'thead',
- 'tr'
-];
-
-// TODO(jmesserly): remove these in favor of the test functions
-const asciiLetters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-
-const _zeroCode = 48;
-const _lowerACode = 97;
-const _lowerZCode = 122;
-const _upperACode = 65;
-const _upperZCode = 90;
+const tableInsertModeElements = {'table', 'tbody', 'tfoot', 'thead', 'tr'};
bool isLetterOrDigit(String? char) => isLetter(char) || isDigit(char);
@@ -438,14 +482,14 @@ bool isLetterOrDigit(String? char) => isLetter(char) || isDigit(char);
bool isLetter(String? char) {
if (char == null) return false;
final cc = char.codeUnitAt(0);
- return cc >= _lowerACode && cc <= _lowerZCode ||
- cc >= _upperACode && cc <= _upperZCode;
+ return cc >= Charcode.lowerA && cc <= Charcode.lowerZ ||
+ cc >= Charcode.upperA && cc <= Charcode.upperZ;
}
bool isDigit(String? char) {
if (char == null) return false;
final cc = char.codeUnitAt(0);
- return cc >= _zeroCode && cc < _zeroCode + 10;
+ return cc >= Charcode.zero && cc < Charcode.zero + 10;
}
bool isHexDigit(String? char) {
@@ -482,20 +526,27 @@ extension AsciiUpperToLower on String {
/// Converts ASCII characters to lowercase.
///
/// Unlike [String.toLowerCase] does not touch non-ASCII characters.
- String toAsciiLowerCase() =>
- String.fromCharCodes(codeUnits.map(_asciiToLower));
+ String toAsciiLowerCase() {
+ if (codeUnits.any(_isUpperCaseCode)) {
+ return String.fromCharCodes(codeUnits.map(_asciiToLower));
+ }
+ return this;
+ }
+
+ static bool _isUpperCaseCode(int c) =>
+ c >= Charcode.upperA && c <= Charcode.upperZ;
- static int _asciiToLower(int c) => (c >= _upperACode && c <= _upperZCode)
- ? c + _lowerACode - _upperACode
- : c;
+ static int _asciiToLower(int c) =>
+ _isUpperCaseCode(c) ? c + Charcode.lowerA - Charcode.upperA : c;
}
// Heading elements need to be ordered
-const headingElements = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
+const headingElementsList = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
+const headingElements = {'h1', 'h2', 'h3', 'h4', 'h5', 'h6'};
-const cdataElements = ['title', 'textarea'];
+const cdataElements = {'title', 'textarea'};
-const rcdataElements = [
+const rcdataElements = {
'style',
'script',
'xmp',
@@ -503,7 +554,7 @@ const rcdataElements = [
'noembed',
'noframes',
'noscript'
-];
+};
// entitiesWindows1252 has to be _ordered_ and needs to have an index. It
// therefore can't be a frozenset.
@@ -3044,3 +3095,262 @@ const Map encodings = {
'windows936': 'gbk',
'x-x-big5': 'big5'
};
+
+const asciiCharacters = [
+ '\u0000',
+ '\u0001',
+ '\u0002',
+ '\u0003',
+ '\u0004',
+ '\u0005',
+ '\u0006',
+ '\u0007',
+ '\u0008',
+ '\u0009',
+ '\u000a',
+ '\u000b',
+ '\u000c',
+ '\u000d',
+ '\u000e',
+ '\u000f',
+ '\u0010',
+ '\u0011',
+ '\u0012',
+ '\u0013',
+ '\u0014',
+ '\u0015',
+ '\u0016',
+ '\u0017',
+ '\u0018',
+ '\u0019',
+ '\u001a',
+ '\u001b',
+ '\u001c',
+ '\u001d',
+ '\u001e',
+ '\u001f',
+ '\u0020',
+ '\u0021',
+ '\u0022',
+ '\u0023',
+ '\u0024',
+ '\u0025',
+ '\u0026',
+ '\u0027',
+ '\u0028',
+ '\u0029',
+ '\u002a',
+ '\u002b',
+ '\u002c',
+ '\u002d',
+ '\u002e',
+ '\u002f',
+ '\u0030',
+ '\u0031',
+ '\u0032',
+ '\u0033',
+ '\u0034',
+ '\u0035',
+ '\u0036',
+ '\u0037',
+ '\u0038',
+ '\u0039',
+ '\u003a',
+ '\u003b',
+ '\u003c',
+ '\u003d',
+ '\u003e',
+ '\u003f',
+ '\u0040',
+ '\u0041',
+ '\u0042',
+ '\u0043',
+ '\u0044',
+ '\u0045',
+ '\u0046',
+ '\u0047',
+ '\u0048',
+ '\u0049',
+ '\u004a',
+ '\u004b',
+ '\u004c',
+ '\u004d',
+ '\u004e',
+ '\u004f',
+ '\u0050',
+ '\u0051',
+ '\u0052',
+ '\u0053',
+ '\u0054',
+ '\u0055',
+ '\u0056',
+ '\u0057',
+ '\u0058',
+ '\u0059',
+ '\u005a',
+ '\u005b',
+ '\u005c',
+ '\u005d',
+ '\u005e',
+ '\u005f',
+ '\u0060',
+ '\u0061',
+ '\u0062',
+ '\u0063',
+ '\u0064',
+ '\u0065',
+ '\u0066',
+ '\u0067',
+ '\u0068',
+ '\u0069',
+ '\u006a',
+ '\u006b',
+ '\u006c',
+ '\u006d',
+ '\u006e',
+ '\u006f',
+ '\u0070',
+ '\u0071',
+ '\u0072',
+ '\u0073',
+ '\u0074',
+ '\u0075',
+ '\u0076',
+ '\u0077',
+ '\u0078',
+ '\u0079',
+ '\u007a',
+ '\u007b',
+ '\u007c',
+ '\u007d',
+ '\u007e',
+ '\u007f',
+ '\u0080',
+ '\u0081',
+ '\u0082',
+ '\u0083',
+ '\u0084',
+ '\u0085',
+ '\u0086',
+ '\u0087',
+ '\u0088',
+ '\u0089',
+ '\u008a',
+ '\u008b',
+ '\u008c',
+ '\u008d',
+ '\u008e',
+ '\u008f',
+ '\u0090',
+ '\u0091',
+ '\u0092',
+ '\u0093',
+ '\u0094',
+ '\u0095',
+ '\u0096',
+ '\u0097',
+ '\u0098',
+ '\u0099',
+ '\u009a',
+ '\u009b',
+ '\u009c',
+ '\u009d',
+ '\u009e',
+ '\u009f',
+ '\u00a0',
+ '\u00a1',
+ '\u00a2',
+ '\u00a3',
+ '\u00a4',
+ '\u00a5',
+ '\u00a6',
+ '\u00a7',
+ '\u00a8',
+ '\u00a9',
+ '\u00aa',
+ '\u00ab',
+ '\u00ac',
+ '\u00ad',
+ '\u00ae',
+ '\u00af',
+ '\u00b0',
+ '\u00b1',
+ '\u00b2',
+ '\u00b3',
+ '\u00b4',
+ '\u00b5',
+ '\u00b6',
+ '\u00b7',
+ '\u00b8',
+ '\u00b9',
+ '\u00ba',
+ '\u00bb',
+ '\u00bc',
+ '\u00bd',
+ '\u00be',
+ '\u00bf',
+ '\u00c0',
+ '\u00c1',
+ '\u00c2',
+ '\u00c3',
+ '\u00c4',
+ '\u00c5',
+ '\u00c6',
+ '\u00c7',
+ '\u00c8',
+ '\u00c9',
+ '\u00ca',
+ '\u00cb',
+ '\u00cc',
+ '\u00cd',
+ '\u00ce',
+ '\u00cf',
+ '\u00d0',
+ '\u00d1',
+ '\u00d2',
+ '\u00d3',
+ '\u00d4',
+ '\u00d5',
+ '\u00d6',
+ '\u00d7',
+ '\u00d8',
+ '\u00d9',
+ '\u00da',
+ '\u00db',
+ '\u00dc',
+ '\u00dd',
+ '\u00de',
+ '\u00df',
+ '\u00e0',
+ '\u00e1',
+ '\u00e2',
+ '\u00e3',
+ '\u00e4',
+ '\u00e5',
+ '\u00e6',
+ '\u00e7',
+ '\u00e8',
+ '\u00e9',
+ '\u00ea',
+ '\u00eb',
+ '\u00ec',
+ '\u00ed',
+ '\u00ee',
+ '\u00ef',
+ '\u00f0',
+ '\u00f1',
+ '\u00f2',
+ '\u00f3',
+ '\u00f4',
+ '\u00f5',
+ '\u00f6',
+ '\u00f7',
+ '\u00f8',
+ '\u00f9',
+ '\u00fa',
+ '\u00fb',
+ '\u00fc',
+ '\u00fd',
+ '\u00fe',
+ '\u00ff'
+];
diff --git a/pkgs/html/lib/src/html_input_stream.dart b/pkgs/html/lib/src/html_input_stream.dart
index b093d3ce30..163992596f 100644
--- a/pkgs/html/lib/src/html_input_stream.dart
+++ b/pkgs/html/lib/src/html_input_stream.dart
@@ -86,20 +86,30 @@ class HtmlInputStream {
errors = Queue();
_offset = 0;
- _chars = [];
final rawChars = _rawChars ??= _decodeBytes(charEncodingName!, _rawBytes!);
+ // Optimistically allocate array, trim it later if there are changes
+ _chars = List.filled(rawChars.length, 0, growable: true);
var skipNewline = false;
var wasSurrogatePair = false;
- for (var i = 0; i < rawChars.length; i++) {
+ var deletedChars = 0;
+
+ /// CodeUnits.length is not free
+ final charsLength = rawChars.length;
+ for (var i = 0; i < charsLength; i++) {
var c = rawChars[i];
if (skipNewline) {
skipNewline = false;
- if (c == newLine) continue;
+ if (c == Charcode.lineFeed) {
+ deletedChars++;
+ continue;
+ }
}
- final isSurrogatePair = _isSurrogatePair(rawChars, i);
+ final isSurrogatePair = _isLeadSurrogate(c) &&
+ i + 1 < charsLength &&
+ _isTrailSurrogate(rawChars[i + 1]);
if (!isSurrogatePair && !wasSurrogatePair) {
if (_invalidUnicode(c)) {
errors.add('invalid-codepoint');
@@ -111,20 +121,24 @@ class HtmlInputStream {
}
wasSurrogatePair = isSurrogatePair;
- if (c == returnCode) {
+ if (c == Charcode.carriageReturn) {
skipNewline = true;
- c = newLine;
+ c = Charcode.lineFeed;
}
- _chars.add(c);
+ _chars[i - deletedChars] = c;
+ }
+ if (deletedChars > 0) {
+ // Remove the null bytes from the end
+ _chars.removeRange(_chars.length - deletedChars, _chars.length);
}
// Free decoded characters if they aren't needed anymore.
if (_rawBytes != null) _rawChars = null;
- // TODO(sigmund): Don't parse the file at all if spans aren't being
- // generated.
- fileInfo = SourceFile.decoded(_chars, url: sourceUrl);
+ if (generateSpans) {
+ fileInfo = SourceFile.decoded(_chars, url: sourceUrl);
+ }
}
void detectEncoding([bool parseMeta = true]) {
@@ -207,16 +221,31 @@ class HtmlInputStream {
/// EOF when EOF is reached.
String? char() {
if (_offset >= _chars.length) return eof;
- return _isSurrogatePair(_chars, _offset)
- ? String.fromCharCodes([_chars[_offset++], _chars[_offset++]])
- : String.fromCharCode(_chars[_offset++]);
+ final firstCharCode = _chars[_offset++];
+ if (firstCharCode < 256) {
+ return asciiCharacters[firstCharCode];
+ }
+ if (_isSurrogatePair(_chars, _offset - 1)) {
+ return String.fromCharCodes([firstCharCode, _chars[_offset++]]);
+ }
+ return String.fromCharCode(firstCharCode);
+ }
+
+ int? peekCodeUnit() {
+ if (_offset >= _chars.length) return null;
+ return _chars[_offset];
}
String? peekChar() {
if (_offset >= _chars.length) return eof;
- return _isSurrogatePair(_chars, _offset)
- ? String.fromCharCodes([_chars[_offset], _chars[_offset + 1]])
- : String.fromCharCode(_chars[_offset]);
+ final firstCharCode = _chars[_offset];
+ if (firstCharCode < 256) {
+ return asciiCharacters[firstCharCode];
+ }
+ if (_isSurrogatePair(_chars, _offset)) {
+ return String.fromCharCodes([firstCharCode, _chars[_offset + 1]]);
+ }
+ return String.fromCharCode(firstCharCode);
}
// Whether the current and next chars indicate a surrogate pair.
@@ -233,12 +262,75 @@ class HtmlInputStream {
bool _isTrailSurrogate(int code) => (code & 0xFC00) == 0xDC00;
/// Returns a string of characters from the stream up to but not
- /// including any character in 'characters' or EOF.
- String charsUntil(String characters, [bool opposite = false]) {
+ /// including any character in 'characters' or EOF. These functions rely
+ /// on the charCode(s) being single-codepoint.
+ String charsUntil(Set charCodes, [bool opposite = false]) {
+ final start = _offset;
+ int? c;
+ while ((c = peekCodeUnit()) != null && charCodes.contains(c!) == opposite) {
+ _offset += 1;
+ }
+
+ return String.fromCharCodes(_chars.sublist(start, _offset));
+ }
+
+ String charsUntil1(int charCode, [bool opposite = false]) {
+ final start = _offset;
+ int? c;
+ while ((c = peekCodeUnit()) != null && (charCode == c!) == opposite) {
+ _offset += 1;
+ }
+
+ return String.fromCharCodes(_chars.sublist(start, _offset));
+ }
+
+ String charsUntil2(int charCode1, int charCode2, [bool opposite = false]) {
+ final start = _offset;
+ int? c;
+ while ((c = peekCodeUnit()) != null &&
+ (charCode1 == c! || charCode2 == c) == opposite) {
+ _offset += 1;
+ }
+
+ return String.fromCharCodes(_chars.sublist(start, _offset));
+ }
+
+ String charsUntil3(int charCode1, int charCode2, int charCode3,
+ [bool opposite = false]) {
+ final start = _offset;
+ int? c;
+ while ((c = peekCodeUnit()) != null &&
+ (charCode1 == c! || charCode2 == c || charCode3 == c) == opposite) {
+ _offset += 1;
+ }
+
+ return String.fromCharCodes(_chars.sublist(start, _offset));
+ }
+
+ String charsUntilAsciiLetter([bool opposite = false]) {
+ final start = _offset;
+ int? c;
+ while ((c = peekCodeUnit()) != null &&
+ ((c! >= Charcode.upperA && c <= Charcode.upperZ) ||
+ (c >= Charcode.lowerA && c <= Charcode.lowerZ)) ==
+ opposite) {
+ _offset += 1;
+ }
+ return String.fromCharCodes(_chars.sublist(start, _offset));
+ }
+
+ static bool _isSpaceCharacter(int c) =>
+ c == Charcode.space ||
+ c == Charcode.lineFeed ||
+ c == Charcode.carriageReturn ||
+ c == Charcode.tab ||
+ c == Charcode.formFeed;
+
+ String charsUntilSpace([bool opposite = false]) {
final start = _offset;
- String? c;
- while ((c = peekChar()) != null && characters.contains(c!) == opposite) {
- _offset += c.codeUnits.length;
+ int? c;
+ while ((c = peekCodeUnit()) != null && _isSpaceCharacter(c!) == opposite) {
+ _offset += 1;
}
return String.fromCharCodes(_chars.sublist(start, _offset));
@@ -257,6 +349,8 @@ class HtmlInputStream {
// TODO(jmesserly): the Python code used a regex to check for this. But
// Dart doesn't let you create a regexp with invalid characters.
bool _invalidUnicode(int c) {
+ // Fast return for common ASCII characters
+ if (0x0020 <= c && c <= 0x007E) return false;
if (0x0001 <= c && c <= 0x0008) return true;
if (0x000E <= c && c <= 0x001F) return true;
if (0x007F <= c && c <= 0x009F) return true;
diff --git a/pkgs/html/lib/src/tokenizer.dart b/pkgs/html/lib/src/tokenizer.dart
index 228087c3db..22676c413c 100644
--- a/pkgs/html/lib/src/tokenizer.dart
+++ b/pkgs/html/lib/src/tokenizer.dart
@@ -5,22 +5,12 @@ import '../parser.dart' show HtmlParser;
import 'constants.dart';
import 'html_input_stream.dart';
import 'token.dart';
+import 'trie.dart';
import 'utils.dart';
// Group entities by their first character, for faster lookups
-// TODO(jmesserly): we could use a better data structure here like a trie, if
-// we had it implemented in Dart.
-Map> entitiesByFirstChar = (() {
- final result = >{};
- for (var k in entities.keys) {
- result.putIfAbsent(k[0], () => []).add(k);
- }
- return result;
-})();
-
// TODO(jmesserly): lots of ways to make this faster:
-// - use char codes everywhere instead of 1-char strings
// - use switch instead of contains, indexOf
// - use switch instead of the sequential if tests
// - avoid string concat
@@ -293,18 +283,11 @@ class HtmlTokenizer implements Iterator {
//
// Consume characters and compare to these to a substring of the
// entity names in the list until the substring no longer matches.
- var filteredEntityList = entitiesByFirstChar[charStack[0]!] ?? const [];
-
- while (charStack.last != eof) {
- final name = charStack.join();
- filteredEntityList = filteredEntityList
- .where((e) => e.startsWith(name))
- .toList(growable: false);
+ dynamic node = entitiesTrieRoot[charStack.last?.codeUnitAt(0)];
- if (filteredEntityList.isEmpty) {
- break;
- }
+ while (node != null && charStack.last != eof) {
charStack.add(stream.char());
+ node = (node as Map)[charStack.last?.codeUnitAt(0)];
}
// At this point we have a string that starts with some characters
@@ -419,13 +402,13 @@ class HtmlTokenizer implements Iterator {
// Directly after emitting a token you switch back to the "data
// state". At that point spaceCharacters are important so they are
// emitted separately.
- _addToken(SpaceCharactersToken(
- '$data${stream.charsUntil(spaceCharacters, true)}'));
+ _addToken(SpaceCharactersToken('$data${stream.charsUntilSpace(true)}'));
// No need to update lastFourChars here, since the first space will
// have already been appended to lastFourChars and will have broken
// any sequences
} else {
- final chars = stream.charsUntil('&<\u0000');
+ final chars = stream.charsUntil3(
+ Charcode.ampersand, Charcode.lessThan, Charcode.nul);
_addToken(CharactersToken('$data$chars'));
}
return true;
@@ -453,10 +436,9 @@ class HtmlTokenizer implements Iterator {
// Directly after emitting a token you switch back to the "data
// state". At that point spaceCharacters are important so they are
// emitted separately.
- _addToken(SpaceCharactersToken(
- '$data${stream.charsUntil(spaceCharacters, true)}'));
+ _addToken(SpaceCharactersToken('$data${stream.charsUntilSpace(true)}'));
} else {
- final chars = stream.charsUntil('&<');
+ final chars = stream.charsUntil2(Charcode.ampersand, Charcode.lessThan);
_addToken(CharactersToken('$data$chars'));
}
return true;
@@ -479,7 +461,7 @@ class HtmlTokenizer implements Iterator {
// Tokenization ends.
return false;
} else {
- final chars = stream.charsUntil('<\u0000');
+ final chars = stream.charsUntil2(Charcode.lessThan, Charcode.nul);
_addToken(CharactersToken('$data$chars'));
}
return true;
@@ -496,7 +478,7 @@ class HtmlTokenizer implements Iterator {
// Tokenization ends.
return false;
} else {
- final chars = stream.charsUntil('<\u0000');
+ final chars = stream.charsUntil2(Charcode.lessThan, Charcode.nul);
_addToken(CharactersToken('$data$chars'));
}
return true;
@@ -511,7 +493,7 @@ class HtmlTokenizer implements Iterator {
_addToken(ParseErrorToken('invalid-codepoint'));
_addToken(CharactersToken('\uFFFD'));
} else {
- _addToken(CharactersToken('$data${stream.charsUntil("\u0000")}'));
+ _addToken(CharactersToken('$data${stream.charsUntil1(Charcode.nul)}'));
}
return true;
}
@@ -784,7 +766,8 @@ class HtmlTokenizer implements Iterator {
} else if (data == eof) {
state = dataState;
} else {
- final chars = stream.charsUntil('<-\u0000');
+ final chars =
+ stream.charsUntil3(Charcode.lessThan, Charcode.hyphen, Charcode.nul);
_addToken(CharactersToken('$data$chars'));
}
return true;
@@ -1009,7 +992,7 @@ class HtmlTokenizer implements Iterator {
bool beforeAttributeNameState() {
final data = stream.char();
if (isWhitespace(data)) {
- stream.charsUntil(spaceCharacters, true);
+ stream.charsUntilSpace(true);
} else if (data != null && isLetter(data)) {
_addAttribute(data);
state = attributeNameState;
@@ -1043,7 +1026,7 @@ class HtmlTokenizer implements Iterator {
state = beforeAttributeValueState;
} else if (isLetter(data)) {
_attributeName.write(data);
- _attributeName.write(stream.charsUntil(asciiLetters, true));
+ _attributeName.write(stream.charsUntilAsciiLetter(true));
leavingThisState = false;
} else if (data == '>') {
// XXX If we emit here the attributes are converted to a dict
@@ -1098,7 +1081,7 @@ class HtmlTokenizer implements Iterator {
bool afterAttributeNameState() {
final data = stream.char();
if (isWhitespace(data)) {
- stream.charsUntil(spaceCharacters, true);
+ stream.charsUntilSpace(true);
} else if (data == '=') {
state = beforeAttributeValueState;
} else if (data == '>') {
@@ -1129,7 +1112,7 @@ class HtmlTokenizer implements Iterator {
bool beforeAttributeValueState() {
final data = stream.char();
if (isWhitespace(data)) {
- stream.charsUntil(spaceCharacters, true);
+ stream.charsUntilSpace(true);
} else if (data == '"') {
_markAttributeValueStart(0);
state = attributeValueDoubleQuotedState;
@@ -1182,7 +1165,8 @@ class HtmlTokenizer implements Iterator {
state = dataState;
} else {
_attributeValue.write(data);
- _attributeValue.write(stream.charsUntil('"&'));
+ _attributeValue
+ .write(stream.charsUntil2(Charcode.doubleQuote, Charcode.ampersand));
}
return true;
}
@@ -1204,7 +1188,8 @@ class HtmlTokenizer implements Iterator {
state = dataState;
} else {
_attributeValue.write(data);
- _attributeValue.write(stream.charsUntil("'&"));
+ _attributeValue
+ .write(stream.charsUntil2(Charcode.singleQuote, Charcode.ampersand));
}
return true;
}
@@ -1232,7 +1217,16 @@ class HtmlTokenizer implements Iterator {
_attributeValue.write('\uFFFD');
} else {
_attributeValue.write(data);
- _attributeValue.write(stream.charsUntil("&>\"'=<`$spaceCharacters"));
+ _attributeValue.write(stream.charsUntil(const {
+ Charcode.ampersand,
+ Charcode.greaterThan,
+ Charcode.doubleQuote,
+ Charcode.singleQuote,
+ Charcode.equals,
+ Charcode.lessThan,
+ Charcode.graveAccent,
+ ...spaceCharacters
+ }));
}
return true;
}
@@ -1278,7 +1272,7 @@ class HtmlTokenizer implements Iterator {
// Make a new comment token and give it as value all the characters
// until the first > or EOF (charsUntil checks for EOF automatically)
// and emit it.
- var data = stream.charsUntil('>');
+ var data = stream.charsUntil1(Charcode.greaterThan);
data = data.replaceAll('\u0000', '\uFFFD');
_addToken(CommentToken(data));
@@ -1397,7 +1391,9 @@ class HtmlTokenizer implements Iterator {
_addToken(currentToken!);
state = dataState;
} else {
- currentStringToken.add(data!).add(stream.charsUntil('-\u0000'));
+ currentStringToken
+ .add(data!)
+ .add(stream.charsUntil2(Charcode.hyphen, Charcode.nul));
}
return true;
}
diff --git a/pkgs/html/lib/src/treebuilder.dart b/pkgs/html/lib/src/treebuilder.dart
index 781f3f6805..e374c7f383 100644
--- a/pkgs/html/lib/src/treebuilder.dart
+++ b/pkgs/html/lib/src/treebuilder.dart
@@ -111,31 +111,31 @@ class TreeBuilder {
// with that name.
final exactNode = target is Node;
- var listElements1 = scopingElements;
- var listElements2 = const <(String, String)>[];
+ var setElements1 = scopingElements;
+ var setElements2 = const <(String, String)>{};
var invert = false;
if (variant != null) {
switch (variant) {
case 'button':
- listElements2 = const [(Namespaces.html, 'button')];
+ setElements2 = const {(Namespaces.html, 'button')};
break;
case 'list':
- listElements2 = const [
+ setElements2 = const {
(Namespaces.html, 'ol'),
(Namespaces.html, 'ul')
- ];
+ };
break;
case 'table':
- listElements1 = const [
+ setElements1 = const {
(Namespaces.html, 'html'),
(Namespaces.html, 'table')
- ];
+ };
break;
case 'select':
- listElements1 = const [
+ setElements1 = const {
(Namespaces.html, 'optgroup'),
(Namespaces.html, 'option')
- ];
+ };
invert = true;
break;
default:
@@ -148,8 +148,8 @@ class TreeBuilder {
exactNode && node == target) {
return true;
} else if (invert !=
- (listElements1.contains(getElementNameTuple(node)) ||
- listElements2.contains(getElementNameTuple(node)))) {
+ (setElements1.contains(getElementNameTuple(node)) ||
+ setElements2.contains(getElementNameTuple(node)))) {
return false;
}
}
diff --git a/pkgs/html/lib/src/trie.dart b/pkgs/html/lib/src/trie.dart
new file mode 100644
index 0000000000..3a8b810382
--- /dev/null
+++ b/pkgs/html/lib/src/trie.dart
@@ -0,0 +1,13973 @@
+// AUTO GENERATED by 'tool/generate_trie.dart'. DO NOT EDIT!
+const entitiesTrieRoot = {
+ 65: {
+ 69: {
+ 108: {
+ 105: {
+ 103: {59: {}}
+ }
+ }
+ },
+ 77: {
+ 80: {59: {}}
+ },
+ 97: {
+ 99: {
+ 117: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 98: {
+ 114: {
+ 101: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 99: {
+ 105: {
+ 114: {
+ 99: {59: {}}
+ }
+ },
+ 121: {59: {}}
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 103: {
+ 114: {
+ 97: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 108: {
+ 112: {
+ 104: {
+ 97: {59: {}}
+ }
+ }
+ },
+ 109: {
+ 97: {
+ 99: {
+ 114: {59: {}}
+ }
+ }
+ },
+ 110: {
+ 100: {59: {}}
+ },
+ 111: {
+ 103: {
+ 111: {
+ 110: {59: {}}
+ }
+ },
+ 112: {
+ 102: {59: {}}
+ }
+ },
+ 112: {
+ 112: {
+ 108: {
+ 121: {
+ 70: {
+ 117: {
+ 110: {
+ 99: {
+ 116: {
+ 105: {
+ 111: {
+ 110: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 114: {
+ 105: {
+ 110: {
+ 103: {59: {}}
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ },
+ 115: {
+ 105: {
+ 103: {
+ 110: {59: {}}
+ }
+ }
+ }
+ },
+ 116: {
+ 105: {
+ 108: {
+ 100: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 117: {
+ 109: {
+ 108: {59: {}}
+ }
+ }
+ },
+ 66: {
+ 97: {
+ 99: {
+ 107: {
+ 115: {
+ 108: {
+ 97: {
+ 115: {
+ 104: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ },
+ 114: {
+ 118: {59: {}},
+ 119: {
+ 101: {
+ 100: {59: {}}
+ }
+ }
+ }
+ },
+ 99: {
+ 121: {59: {}}
+ },
+ 101: {
+ 99: {
+ 97: {
+ 117: {
+ 115: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 114: {
+ 110: {
+ 111: {
+ 117: {
+ 108: {
+ 108: {
+ 105: {
+ 115: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 116: {
+ 97: {59: {}}
+ }
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 111: {
+ 112: {
+ 102: {59: {}}
+ }
+ },
+ 114: {
+ 101: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ }
+ },
+ 117: {
+ 109: {
+ 112: {
+ 101: {
+ 113: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 67: {
+ 72: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 79: {
+ 80: {
+ 89: {59: {}}
+ }
+ },
+ 97: {
+ 99: {
+ 117: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ },
+ 112: {
+ 59: {},
+ 105: {
+ 116: {
+ 97: {
+ 108: {
+ 68: {
+ 105: {
+ 102: {
+ 102: {
+ 101: {
+ 114: {
+ 101: {
+ 110: {
+ 116: {
+ 105: {
+ 97: {
+ 108: {
+ 68: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 121: {
+ 108: {
+ 101: {
+ 121: {
+ 115: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 99: {
+ 97: {
+ 114: {
+ 111: {
+ 110: {59: {}}
+ }
+ }
+ },
+ 101: {
+ 100: {
+ 105: {
+ 108: {59: {}}
+ }
+ }
+ },
+ 105: {
+ 114: {
+ 99: {59: {}}
+ }
+ },
+ 111: {
+ 110: {
+ 105: {
+ 110: {
+ 116: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 100: {
+ 111: {
+ 116: {59: {}}
+ }
+ },
+ 101: {
+ 100: {
+ 105: {
+ 108: {
+ 108: {
+ 97: {59: {}}
+ }
+ }
+ }
+ },
+ 110: {
+ 116: {
+ 101: {
+ 114: {
+ 68: {
+ 111: {
+ 116: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 104: {
+ 105: {59: {}}
+ },
+ 105: {
+ 114: {
+ 99: {
+ 108: {
+ 101: {
+ 68: {
+ 111: {
+ 116: {59: {}}
+ }
+ },
+ 77: {
+ 105: {
+ 110: {
+ 117: {
+ 115: {59: {}}
+ }
+ }
+ }
+ },
+ 80: {
+ 108: {
+ 117: {
+ 115: {59: {}}
+ }
+ }
+ },
+ 84: {
+ 105: {
+ 109: {
+ 101: {
+ 115: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 108: {
+ 111: {
+ 99: {
+ 107: {
+ 119: {
+ 105: {
+ 115: {
+ 101: {
+ 67: {
+ 111: {
+ 110: {
+ 116: {
+ 111: {
+ 117: {
+ 114: {
+ 73: {
+ 110: {
+ 116: {
+ 101: {
+ 103: {
+ 114: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 115: {
+ 101: {
+ 67: {
+ 117: {
+ 114: {
+ 108: {
+ 121: {
+ 68: {
+ 111: {
+ 117: {
+ 98: {
+ 108: {
+ 101: {
+ 81: {
+ 117: {
+ 111: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 81: {
+ 117: {
+ 111: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 111: {
+ 108: {
+ 111: {
+ 110: {
+ 59: {},
+ 101: {59: {}}
+ }
+ }
+ },
+ 110: {
+ 103: {
+ 114: {
+ 117: {
+ 101: {
+ 110: {
+ 116: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 105: {
+ 110: {
+ 116: {59: {}}
+ }
+ },
+ 116: {
+ 111: {
+ 117: {
+ 114: {
+ 73: {
+ 110: {
+ 116: {
+ 101: {
+ 103: {
+ 114: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 112: {
+ 102: {59: {}},
+ 114: {
+ 111: {
+ 100: {
+ 117: {
+ 99: {
+ 116: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ },
+ 117: {
+ 110: {
+ 116: {
+ 101: {
+ 114: {
+ 67: {
+ 108: {
+ 111: {
+ 99: {
+ 107: {
+ 119: {
+ 105: {
+ 115: {
+ 101: {
+ 67: {
+ 111: {
+ 110: {
+ 116: {
+ 111: {
+ 117: {
+ 114: {
+ 73: {
+ 110: {
+ 116: {
+ 101: {
+ 103: {
+ 114: {
+ 97: {
+ 108: {
+ 59: {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 114: {
+ 111: {
+ 115: {
+ 115: {59: {}}
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ }
+ },
+ 117: {
+ 112: {
+ 59: {},
+ 67: {
+ 97: {
+ 112: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 68: {
+ 68: {
+ 59: {},
+ 111: {
+ 116: {
+ 114: {
+ 97: {
+ 104: {
+ 100: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ },
+ 74: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 83: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 90: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 97: {
+ 103: {
+ 103: {
+ 101: {
+ 114: {59: {}}
+ }
+ }
+ },
+ 114: {
+ 114: {59: {}}
+ },
+ 115: {
+ 104: {
+ 118: {59: {}}
+ }
+ }
+ },
+ 99: {
+ 97: {
+ 114: {
+ 111: {
+ 110: {59: {}}
+ }
+ }
+ },
+ 121: {59: {}}
+ },
+ 101: {
+ 108: {
+ 59: {},
+ 116: {
+ 97: {59: {}}
+ }
+ }
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 105: {
+ 97: {
+ 99: {
+ 114: {
+ 105: {
+ 116: {
+ 105: {
+ 99: {
+ 97: {
+ 108: {
+ 65: {
+ 99: {
+ 117: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 68: {
+ 111: {
+ 116: {59: {}},
+ 117: {
+ 98: {
+ 108: {
+ 101: {
+ 65: {
+ 99: {
+ 117: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 71: {
+ 114: {
+ 97: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 84: {
+ 105: {
+ 108: {
+ 100: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 109: {
+ 111: {
+ 110: {
+ 100: {59: {}}
+ }
+ }
+ }
+ },
+ 102: {
+ 102: {
+ 101: {
+ 114: {
+ 101: {
+ 110: {
+ 116: {
+ 105: {
+ 97: {
+ 108: {
+ 68: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 111: {
+ 112: {
+ 102: {59: {}}
+ },
+ 116: {
+ 59: {},
+ 68: {
+ 111: {
+ 116: {59: {}}
+ }
+ },
+ 69: {
+ 113: {
+ 117: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 117: {
+ 98: {
+ 108: {
+ 101: {
+ 67: {
+ 111: {
+ 110: {
+ 116: {
+ 111: {
+ 117: {
+ 114: {
+ 73: {
+ 110: {
+ 116: {
+ 101: {
+ 103: {
+ 114: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 68: {
+ 111: {
+ 116: {59: {}},
+ 119: {
+ 110: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 76: {
+ 101: {
+ 102: {
+ 116: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ },
+ 82: {
+ 105: {
+ 103: {
+ 104: {
+ 116: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 84: {
+ 101: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 111: {
+ 110: {
+ 103: {
+ 76: {
+ 101: {
+ 102: {
+ 116: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ },
+ 82: {
+ 105: {
+ 103: {
+ 104: {
+ 116: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 82: {
+ 105: {
+ 103: {
+ 104: {
+ 116: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 82: {
+ 105: {
+ 103: {
+ 104: {
+ 116: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ },
+ 84: {
+ 101: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 85: {
+ 112: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ },
+ 68: {
+ 111: {
+ 119: {
+ 110: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 86: {
+ 101: {
+ 114: {
+ 116: {
+ 105: {
+ 99: {
+ 97: {
+ 108: {
+ 66: {
+ 97: {
+ 114: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 119: {
+ 110: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {
+ 59: {},
+ 66: {
+ 97: {
+ 114: {59: {}}
+ }
+ },
+ 85: {
+ 112: {
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 66: {
+ 114: {
+ 101: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 76: {
+ 101: {
+ 102: {
+ 116: {
+ 82: {
+ 105: {
+ 103: {
+ 104: {
+ 116: {
+ 86: {
+ 101: {
+ 99: {
+ 116: {
+ 111: {
+ 114: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 84: {
+ 101: {
+ 101: {
+ 86: {
+ 101: {
+ 99: {
+ 116: {
+ 111: {
+ 114: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 86: {
+ 101: {
+ 99: {
+ 116: {
+ 111: {
+ 114: {
+ 59: {},
+ 66: {
+ 97: {
+ 114: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 82: {
+ 105: {
+ 103: {
+ 104: {
+ 116: {
+ 84: {
+ 101: {
+ 101: {
+ 86: {
+ 101: {
+ 99: {
+ 116: {
+ 111: {
+ 114: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 86: {
+ 101: {
+ 99: {
+ 116: {
+ 111: {
+ 114: {
+ 59: {},
+ 66: {
+ 97: {
+ 114: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 84: {
+ 101: {
+ 101: {
+ 59: {},
+ 65: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 97: {
+ 114: {
+ 114: {
+ 111: {
+ 119: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ },
+ 116: {
+ 114: {
+ 111: {
+ 107: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 69: {
+ 78: {
+ 71: {59: {}}
+ },
+ 84: {
+ 72: {59: {}}
+ },
+ 97: {
+ 99: {
+ 117: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 99: {
+ 97: {
+ 114: {
+ 111: {
+ 110: {59: {}}
+ }
+ }
+ },
+ 105: {
+ 114: {
+ 99: {59: {}}
+ }
+ },
+ 121: {59: {}}
+ },
+ 100: {
+ 111: {
+ 116: {59: {}}
+ }
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 103: {
+ 114: {
+ 97: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 108: {
+ 101: {
+ 109: {
+ 101: {
+ 110: {
+ 116: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 109: {
+ 97: {
+ 99: {
+ 114: {59: {}}
+ }
+ },
+ 112: {
+ 116: {
+ 121: {
+ 83: {
+ 109: {
+ 97: {
+ 108: {
+ 108: {
+ 83: {
+ 113: {
+ 117: {
+ 97: {
+ 114: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 86: {
+ 101: {
+ 114: {
+ 121: {
+ 83: {
+ 109: {
+ 97: {
+ 108: {
+ 108: {
+ 83: {
+ 113: {
+ 117: {
+ 97: {
+ 114: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 111: {
+ 103: {
+ 111: {
+ 110: {59: {}}
+ }
+ },
+ 112: {
+ 102: {59: {}}
+ }
+ },
+ 112: {
+ 115: {
+ 105: {
+ 108: {
+ 111: {
+ 110: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 113: {
+ 117: {
+ 97: {
+ 108: {
+ 59: {},
+ 84: {
+ 105: {
+ 108: {
+ 100: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ },
+ 105: {
+ 108: {
+ 105: {
+ 98: {
+ 114: {
+ 105: {
+ 117: {
+ 109: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ },
+ 105: {
+ 109: {59: {}}
+ }
+ },
+ 116: {
+ 97: {59: {}}
+ },
+ 117: {
+ 109: {
+ 108: {59: {}}
+ }
+ },
+ 120: {
+ 105: {
+ 115: {
+ 116: {
+ 115: {59: {}}
+ }
+ }
+ },
+ 112: {
+ 111: {
+ 110: {
+ 101: {
+ 110: {
+ 116: {
+ 105: {
+ 97: {
+ 108: {
+ 69: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 70: {
+ 99: {
+ 121: {59: {}}
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 105: {
+ 108: {
+ 108: {
+ 101: {
+ 100: {
+ 83: {
+ 109: {
+ 97: {
+ 108: {
+ 108: {
+ 83: {
+ 113: {
+ 117: {
+ 97: {
+ 114: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 86: {
+ 101: {
+ 114: {
+ 121: {
+ 83: {
+ 109: {
+ 97: {
+ 108: {
+ 108: {
+ 83: {
+ 113: {
+ 117: {
+ 97: {
+ 114: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 111: {
+ 112: {
+ 102: {59: {}}
+ },
+ 114: {
+ 65: {
+ 108: {
+ 108: {59: {}}
+ }
+ }
+ },
+ 117: {
+ 114: {
+ 105: {
+ 101: {
+ 114: {
+ 116: {
+ 114: {
+ 102: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ }
+ }
+ },
+ 71: {
+ 74: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 84: {59: {}},
+ 97: {
+ 109: {
+ 109: {
+ 97: {
+ 59: {},
+ 100: {59: {}}
+ }
+ }
+ }
+ },
+ 98: {
+ 114: {
+ 101: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 99: {
+ 101: {
+ 100: {
+ 105: {
+ 108: {59: {}}
+ }
+ }
+ },
+ 105: {
+ 114: {
+ 99: {59: {}}
+ }
+ },
+ 121: {59: {}}
+ },
+ 100: {
+ 111: {
+ 116: {59: {}}
+ }
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 103: {59: {}},
+ 111: {
+ 112: {
+ 102: {59: {}}
+ }
+ },
+ 114: {
+ 101: {
+ 97: {
+ 116: {
+ 101: {
+ 114: {
+ 69: {
+ 113: {
+ 117: {
+ 97: {
+ 108: {
+ 59: {},
+ 76: {
+ 101: {
+ 115: {
+ 115: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 70: {
+ 117: {
+ 108: {
+ 108: {
+ 69: {
+ 113: {
+ 117: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 71: {
+ 114: {
+ 101: {
+ 97: {
+ 116: {
+ 101: {
+ 114: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ },
+ 76: {
+ 101: {
+ 115: {
+ 115: {59: {}}
+ }
+ }
+ },
+ 83: {
+ 108: {
+ 97: {
+ 110: {
+ 116: {
+ 69: {
+ 113: {
+ 117: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 84: {
+ 105: {
+ 108: {
+ 100: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ }
+ },
+ 116: {59: {}}
+ },
+ 72: {
+ 65: {
+ 82: {
+ 68: {
+ 99: {
+ 121: {59: {}}
+ }
+ }
+ }
+ },
+ 97: {
+ 99: {
+ 101: {
+ 107: {59: {}}
+ }
+ },
+ 116: {59: {}}
+ },
+ 99: {
+ 105: {
+ 114: {
+ 99: {59: {}}
+ }
+ }
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 105: {
+ 108: {
+ 98: {
+ 101: {
+ 114: {
+ 116: {
+ 83: {
+ 112: {
+ 97: {
+ 99: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 111: {
+ 112: {
+ 102: {59: {}}
+ },
+ 114: {
+ 105: {
+ 122: {
+ 111: {
+ 110: {
+ 116: {
+ 97: {
+ 108: {
+ 76: {
+ 105: {
+ 110: {
+ 101: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ },
+ 116: {
+ 114: {
+ 111: {
+ 107: {59: {}}
+ }
+ }
+ }
+ },
+ 117: {
+ 109: {
+ 112: {
+ 68: {
+ 111: {
+ 119: {
+ 110: {
+ 72: {
+ 117: {
+ 109: {
+ 112: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 69: {
+ 113: {
+ 117: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 73: {
+ 69: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 74: {
+ 108: {
+ 105: {
+ 103: {59: {}}
+ }
+ }
+ },
+ 79: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 97: {
+ 99: {
+ 117: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 99: {
+ 105: {
+ 114: {
+ 99: {59: {}}
+ }
+ },
+ 121: {59: {}}
+ },
+ 100: {
+ 111: {
+ 116: {59: {}}
+ }
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 103: {
+ 114: {
+ 97: {
+ 118: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 109: {
+ 59: {},
+ 97: {
+ 99: {
+ 114: {59: {}}
+ },
+ 103: {
+ 105: {
+ 110: {
+ 97: {
+ 114: {
+ 121: {
+ 73: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 112: {
+ 108: {
+ 105: {
+ 101: {
+ 115: {59: {}}
+ }
+ }
+ }
+ }
+ },
+ 110: {
+ 116: {
+ 59: {},
+ 101: {
+ 103: {
+ 114: {
+ 97: {
+ 108: {59: {}}
+ }
+ }
+ },
+ 114: {
+ 115: {
+ 101: {
+ 99: {
+ 116: {
+ 105: {
+ 111: {
+ 110: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 118: {
+ 105: {
+ 115: {
+ 105: {
+ 98: {
+ 108: {
+ 101: {
+ 67: {
+ 111: {
+ 109: {
+ 109: {
+ 97: {59: {}}
+ }
+ }
+ }
+ },
+ 84: {
+ 105: {
+ 109: {
+ 101: {
+ 115: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 111: {
+ 103: {
+ 111: {
+ 110: {59: {}}
+ }
+ },
+ 112: {
+ 102: {59: {}}
+ },
+ 116: {
+ 97: {59: {}}
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ }
+ },
+ 116: {
+ 105: {
+ 108: {
+ 100: {
+ 101: {59: {}}
+ }
+ }
+ }
+ },
+ 117: {
+ 107: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 109: {
+ 108: {59: {}}
+ }
+ }
+ },
+ 74: {
+ 99: {
+ 105: {
+ 114: {
+ 99: {59: {}}
+ }
+ },
+ 121: {59: {}}
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 111: {
+ 112: {
+ 102: {59: {}}
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ },
+ 101: {
+ 114: {
+ 99: {
+ 121: {59: {}}
+ }
+ }
+ }
+ },
+ 117: {
+ 107: {
+ 99: {
+ 121: {59: {}}
+ }
+ }
+ }
+ },
+ 75: {
+ 72: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 74: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 97: {
+ 112: {
+ 112: {
+ 97: {59: {}}
+ }
+ }
+ },
+ 99: {
+ 101: {
+ 100: {
+ 105: {
+ 108: {59: {}}
+ }
+ }
+ },
+ 121: {59: {}}
+ },
+ 102: {
+ 114: {59: {}}
+ },
+ 111: {
+ 112: {
+ 102: {59: {}}
+ }
+ },
+ 115: {
+ 99: {
+ 114: {59: {}}
+ }
+ }
+ },
+ 76: {
+ 74: {
+ 99: {
+ 121: {59: {}}
+ }
+ },
+ 84: {59: {}},
+ 97: {
+ 99: {
+ 117: {
+ 116: {
+ 101: {59: {}}
+ }
+ }
+ },
+ 109: {
+ 98: {
+ 100: {
+ 97: {59: {}}
+ }
+ }
+ },
+ 110: {
+ 103: {59: {}}
+ },
+ 112: {
+ 108: {
+ 97: {
+ 99: {
+ 101: {
+ 116: {
+ 114: {
+ 102: {59: {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ 114: {
+ 114: {59: