@mrhenry/twig-html-parser 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1 +1,46 @@
1
1
  # Changelog
2
+
3
+ ## 0.1.2 (2026-09-26)
4
+
5
+ * Bounded the hybrid parser against pathological nesting. `pairTree` now walks
6
+ the AST iteratively instead of by recursion, and both the element stack
7
+ (`buildTree`) and the twig-block stack (`pairTwigBlocks`) are capped at
8
+ `4096` open levels; past the cap an element or block is kept as a leaf. This
9
+ removes the stack-overflow denial of service a deeply nested untrusted
10
+ template could trigger.
11
+ * Lowered the `MAX_ELEMENT_DEPTH`/`MAX_BLOCK_DEPTH` caps from `4096` to `256`.
12
+ The caps bound the tree this package builds, but recursive consumers (the
13
+ Prettier printer overflows at roughly 1000 nested elements) could still be
14
+ overflowed by a tree the parser considered valid; `256` keeps a promised
15
+ tree safe to walk.
16
+ * Added `test/limits.test.js` covering 20k-deep element and block nesting.
17
+
18
+ * Added a tokenizer corpus test derived from the WPT html5lib suite
19
+ (`wpt/html/syntax/parsing/resources/*.dat`, ~1959 inputs, vendored under
20
+ `test/fixtures/wpt-html5lib-inputs.json`). Every input must tokenize to a
21
+ contiguous, source-ordered token list with exact offsets and without
22
+ hanging; a few cases assert tokenizer-level spec outcomes (including
23
+ unquoted attribute values such as `<div id=foo>`, where `>` ends the value
24
+ and a trailing `/` is part of it).
25
+ * The raw-text end tag is now consumed with the full tag machinery, honouring
26
+ quoted attribute values, so `</script foo=">" dd>` closes at its real `>`
27
+ instead of at the `>` inside the quoted value. An unterminated `</script`
28
+ before EOF stays raw text and leaves the element open, as the spec requires.
29
+ * HTML comments now also close on `--!>` (the spec's comment-end-bang state, a
30
+ parse error) in addition to `-->`, so `<!-- BAR --!>BAZ` no longer swallows
31
+ the trailing text.
32
+ * Fixed raw-text and RCDATA elements closing on an inappropriate end tag. The
33
+ tokenizer now follows the spec's "appropriate end tag" rule instead of a bare
34
+ prefix search, so `<script>var x = "</scripture>";</script>` keeps
35
+ `</scripture>` as script text and closes on the real `</script>`.
36
+ * `xmp`, `iframe`, `noembed` and `noframes` are now tokenized as raw text
37
+ (their content is not parsed as markup), matching the spec's RAWTEXT
38
+ elements. `noscript` and the obsolete `plaintext` stay parsed as markup.
39
+ * End tags with a tail no longer overwrite the tag name: `</div class=x>` is an
40
+ end tag for `div`, not for `class=x`, so it correctly closes an open `<div>`.
41
+ * Fixed two tokenizer bugs that produced overlapping or dropped tokens: a bogus
42
+ comment (`<!- x>`, `<?`) no longer also flushes a duplicate `text` token, and
43
+ `<?` at end of input now emits its comment instead of nothing.
44
+ * Fixed an infinite loop when an end tag carried an equals sign in its tail
45
+ (e.g. `</div class=x>`); the tokenizer now consumes the offending character
46
+ and terminates
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrhenry/twig-html-parser",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -11,6 +11,6 @@
11
11
  "test": "node --test test/*.test.js"
12
12
  },
13
13
  "dependencies": {
14
- "@mrhenry/twig-tokenizer": "^0.1.1"
14
+ "@mrhenry/twig-tokenizer": "^0.1.2"
15
15
  }
16
16
  }
@@ -22,8 +22,13 @@
22
22
 
23
23
  /** Whitespace characters inside HTML tags. */
24
24
  const WS = ' \t\n\f\r';
25
- /** Elements whose content is raw text (not parsed as markup). */
26
- const RAWTEXT_ELEMENTS = new Set(['script', 'style']);
25
+ /**
26
+ * Elements whose content is raw text (not parsed as markup). Mirrors the
27
+ * spec's RAWTEXT / script-data elements. `noscript` and the obsolete
28
+ * `plaintext` are intentionally excluded: `noscript` depends on the scripting
29
+ * flag and `plaintext` runs to EOF without an end tag.
30
+ */
31
+ const RAWTEXT_ELEMENTS = new Set(['script', 'style', 'xmp', 'iframe', 'noembed', 'noframes']);
27
32
  /** Elements whose content is RCDATA (treated as raw text here). */
28
33
  const RCDATA_ELEMENTS = new Set(['textarea', 'title']);
29
34
 
@@ -350,7 +355,8 @@ export function tokenizeHtml(atoms, source) {
350
355
  /**
351
356
  * Consumes a `<!-- ... -->` comment across text and twig atoms. Returns the
352
357
  * raw text consumed; when the comment is unterminated the rest of the input
353
- * is consumed.
358
+ * is consumed. The spec's comment-end-bang state also closes on `--!>`
359
+ * (a parse error), so both terminators are recognised.
354
360
  *
355
361
  * @returns {{text: string, end: number}}
356
362
  */
@@ -369,8 +375,15 @@ export function tokenizeHtml(atoms, source) {
369
375
  break;
370
376
  }
371
377
  const raw = a.raw;
372
- const idx = raw.indexOf('-->', cursor.pos);
373
- const limit = idx === -1 ? raw.length : idx + 3;
378
+ const closeIdx = raw.indexOf('-->', cursor.pos);
379
+ const bangIdx = raw.indexOf('--!>', cursor.pos);
380
+ let idx = closeIdx;
381
+ let length = 3;
382
+ if (bangIdx !== -1 && (closeIdx === -1 || bangIdx < closeIdx)) {
383
+ idx = bangIdx;
384
+ length = 4;
385
+ }
386
+ const limit = idx === -1 ? raw.length : idx + length;
374
387
  out += raw.slice(cursor.pos, limit);
375
388
  cursor.pos = limit;
376
389
  end = a.rawStart + limit;
@@ -382,13 +395,19 @@ export function tokenizeHtml(atoms, source) {
382
395
  }
383
396
 
384
397
  /**
385
- * Scans raw text up to `</tag` (case-insensitive) or a twig atom.
398
+ * Scans raw text up to an *appropriate end tag* for `tagName` or a twig
399
+ * atom. The spec's RAWTEXT/RCDATA end-tag-open states only treat `</name`
400
+ * as an end tag when the name is complete, i.e. followed by whitespace, `/`
401
+ * or `>`; otherwise the `</name` run is ordinary raw text. A bare prefix
402
+ * such as `</scripture>` must not close a `<script>`.
386
403
  *
387
404
  * @param {string} tagName
388
405
  * @returns {{text: string, textStart: number, textEnd: number, found: boolean, endTag: string, endTagStart: number, endTagEnd: number}}
389
406
  */
390
407
  function scanRawText(tagName) {
391
408
  const lowerTag = tagName.toLowerCase();
409
+ const marker = `</${lowerTag}`;
410
+ const markerLength = marker.length;
392
411
  const start = cursor.offset();
393
412
  let out = '';
394
413
  let textEnd = start;
@@ -398,26 +417,98 @@ export function tokenizeHtml(atoms, source) {
398
417
  break; // twig or end of input
399
418
  }
400
419
  const raw = a.raw;
401
- const idx = raw.toLowerCase().indexOf(`</${lowerTag}`, cursor.pos);
420
+ const lower = raw.toLowerCase();
421
+ let searchFrom = cursor.pos;
422
+ let idx = -1;
423
+ for (;;) {
424
+ const candidate = lower.indexOf(marker, searchFrom);
425
+ if (candidate === -1) {
426
+ break;
427
+ }
428
+ const after = raw[candidate + markerLength];
429
+ // only whitespace, `/` or `>` makes this an appropriate end tag;
430
+ // anything else (or end of input) is raw text and the scan continues
431
+ if (after === undefined || after === ' ' || after === '\t' || after === '\n' || after === '\f' || after === '\r' || after === '/' || after === '>') {
432
+ idx = candidate;
433
+ break;
434
+ }
435
+ searchFrom = candidate + markerLength;
436
+ }
402
437
  const limit = idx === -1 ? raw.length : idx;
403
438
  out += raw.slice(cursor.pos, limit);
404
439
  cursor.pos = limit;
405
440
  textEnd = a.rawStart + limit;
406
441
  if (idx !== -1) {
407
- // consume `</tag` plus whitespace up to `>`
408
- let i = idx;
409
- while (i < raw.length && raw[i] !== '>') {
410
- i += 1;
442
+ // consume the end tag through its closing `>`, honouring quoted
443
+ // attribute values so a `>` inside `</script foo=">">` does not
444
+ // terminate the tag early (spec: script data / RAWTEXT end tag
445
+ // name states reuse the ordinary tag machinery)
446
+ const endTagStart = a.rawStart + idx;
447
+ const consumed = consumeEndTag();
448
+ if (consumed === -1) {
449
+ // no `>` before EOF: the `</name` run is raw text (spec's
450
+ // eof-in-script-data behaviour), so keep it and stop
451
+ out += source.slice(endTagStart);
452
+ textEnd = source.length;
453
+ cursor.pos = raw.length;
454
+ break;
411
455
  }
412
- const endTagEnd = i < raw.length ? a.rawStart + i + 1 : a.rawStart + raw.length;
413
- const endTag = raw.slice(idx, endTagEnd - a.rawStart);
414
- cursor.pos = endTagEnd - a.rawStart;
415
- return { text: out, textStart: start, textEnd, found: true, endTag, endTagStart: a.rawStart + idx, endTagEnd };
456
+ return {
457
+ text: out,
458
+ textStart: start,
459
+ textEnd,
460
+ found: true,
461
+ endTag: source.slice(endTagStart, consumed),
462
+ endTagStart,
463
+ endTagEnd: consumed,
464
+ };
416
465
  }
417
466
  }
418
467
  return { text: out, textStart: start, textEnd, found: false, endTag: '', endTagStart: 0, endTagEnd: 0 };
419
468
  }
420
469
 
470
+ /**
471
+ * Consumes an end tag from the current position (the `<` of `</name`) through
472
+ * its closing `>`, honouring double- and single-quoted attribute values so a
473
+ * `>` inside a quoted value does not end the tag. Twig atoms inside the tag
474
+ * are consumed whole. Returns the absolute offset just past the `>`, or `-1`
475
+ * when the tag is unterminated at end of input.
476
+ *
477
+ * @returns {number} Absolute end offset of the end tag, or -1 at EOF.
478
+ */
479
+ function consumeEndTag() {
480
+ // starting quote state: null (outside), '"' or "'"
481
+ let quote = null;
482
+ for (;;) {
483
+ const a = cursor.textAtom();
484
+ if (!a) {
485
+ if (cursor.atTwig()) {
486
+ cursor.takeTwig();
487
+ continue;
488
+ }
489
+ return -1;
490
+ }
491
+ const raw = a.raw;
492
+ let i = cursor.pos;
493
+ for (; i < raw.length; i += 1) {
494
+ const ch = raw[i];
495
+ if (quote !== null) {
496
+ if (ch === quote) {
497
+ quote = null;
498
+ }
499
+ continue;
500
+ }
501
+ if (ch === '"' || ch === "'") {
502
+ quote = ch;
503
+ } else if (ch === '>') {
504
+ cursor.pos = i + 1;
505
+ return a.rawStart + i + 1;
506
+ }
507
+ }
508
+ cursor.pos = i;
509
+ }
510
+ }
511
+
421
512
  /**
422
513
  * Commits the current attribute (if any) to the tag's attribute list.
423
514
  */
@@ -583,7 +674,6 @@ export function tokenizeHtml(atoms, source) {
583
674
  if (c === '?') {
584
675
  cursor.next();
585
676
  declStart = /** @type {TagState} */ (tag).rawStart;
586
- tag = null;
587
677
  state = 'bogusComment';
588
678
  break;
589
679
  }
@@ -661,11 +751,11 @@ export function tokenizeHtml(atoms, source) {
661
751
  state = 'data';
662
752
  break;
663
753
  }
664
- // unexpected character: keep scanning the end tag name
665
- const end = scanName();
666
- /** @type {TagState} */ (tag).nameRaw = end.text;
667
- /** @type {TagState} */ (tag).name = end.text.toLowerCase();
668
- /** @type {TagState} */ (tag).nameEnd = end.end;
754
+ // The spec reuses the "before attribute name" states for end tags:
755
+ // an unexpected character is a parse error and the tag name is
756
+ // left untouched. `</div class=x>` is still an end tag for `div`,
757
+ // so keep scanning to `>` without overwriting the name.
758
+ cursor.next();
669
759
  break;
670
760
  }
671
761
 
@@ -1012,6 +1102,9 @@ export function tokenizeHtml(atoms, source) {
1012
1102
  case 'bogusComment': {
1013
1103
  const rest = readTagRest();
1014
1104
  tokens.push(htmlToken('comment', source.slice(declStart, rest.end), declStart, rest.end));
1105
+ // clear the pending markup so the end-of-input flush cannot emit a
1106
+ // second, overlapping text token for the same span
1107
+ tag = null;
1015
1108
  state = 'data';
1016
1109
  break;
1017
1110
  }
package/src/parser.js CHANGED
@@ -183,7 +183,12 @@ export function buildTree(tokens) {
183
183
  ),
184
184
  });
185
185
  append(element);
186
- if (!token.selfClosing && !VOID_ELEMENTS.has(token.name ?? '')) {
186
+ // Cap the open-element stack so a pathological input (deeply nested
187
+ // tags) cannot build an unboundedly deep tree. Past the cap the
188
+ // element is treated as a leaf: its would-be children become its
189
+ // siblings, which keeps memory and every downstream traversal
190
+ // bounded while preserving the source text.
191
+ if (!token.selfClosing && !VOID_ELEMENTS.has(token.name ?? '') && stack.length <= MAX_ELEMENT_DEPTH) {
187
192
  stack.push(element);
188
193
  }
189
194
  break;
@@ -238,6 +243,25 @@ export function buildTree(tokens) {
238
243
  return root;
239
244
  }
240
245
 
246
+ /**
247
+ * The deepest open-element stack the tree builder maintains. A source nested
248
+ * past this depth is flattened rather than allowed to grow without bound: the
249
+ * cap keeps `buildTree` linear in memory and prevents deep recursion in this
250
+ * package's own traversals and in consumers that walk the AST recursively.
251
+ */
252
+ const MAX_ELEMENT_DEPTH = 256;
253
+
254
+ /**
255
+ * The deepest open-block stack {@link pairTwigBlocks} maintains. As with
256
+ * {@link MAX_ELEMENT_DEPTH}, nesting past the cap degrades to flat leaves
257
+ * rather than growing an unboundedly deep tree.
258
+ *
259
+ * The cap is kept well below the stack limit of recursive consumers (the
260
+ * Prettier printer overflows at roughly 1000 nested elements), so a tree this
261
+ * package promises to build can also be walked safely by its callers.
262
+ */
263
+ const MAX_BLOCK_DEPTH = 256;
264
+
241
265
  /** Void elements that never have an end tag. */
242
266
  const VOID_ELEMENTS = new Set([
243
267
  'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link',
@@ -251,24 +275,23 @@ const VOID_ELEMENTS = new Set([
251
275
  * @param {AstNode} root
252
276
  */
253
277
  function pairTree(root) {
254
- /** @param {AstNode} n */
255
- const walk = (n) => {
278
+ // Iterative post-order-free walk: the tree can be arbitrarily deep (up to
279
+ // MAX_ELEMENT_DEPTH), so recursion here would risk a stack overflow on
280
+ // untrusted templates. Children are paired before being enqueued, matching
281
+ // the previous depth-first recursion order.
282
+ /** @type {AstNode[]} */
283
+ const stack = [root];
284
+ while (stack.length > 0) {
285
+ const n = /** @type {AstNode} */ (stack.pop());
256
286
  if (Array.isArray(n.children)) {
257
287
  n.children = /** @type {AstNode[]} */ (pairTwigBlocks(n.children));
258
288
  for (const child of n.children) {
259
- walk(child);
289
+ stack.push(child);
260
290
  }
261
291
  }
262
292
  if (n.type === 'element' && Array.isArray(n.attrs)) {
263
293
  n.attrs = pairTwigBlocks(n.attrs);
264
294
  }
265
- };
266
- const children = root.children;
267
- if (Array.isArray(children)) {
268
- root.children = /** @type {AstNode[]} */ (pairTwigBlocks(children));
269
- for (const child of root.children) {
270
- walk(child);
271
- }
272
295
  }
273
296
  }
274
297
 
@@ -290,6 +313,13 @@ export function pairTwigBlocks(items) {
290
313
  const twig = /** @type {AstNode} */ (item);
291
314
  const atom = /** @type {Atom} */ (twig.atom);
292
315
  if (isBlockOpen(atom)) {
316
+ if (stack.length >= MAX_BLOCK_DEPTH) {
317
+ // Past the cap a block-open is kept as a leaf, so nesting cannot
318
+ // grow without bound. Its matching close will not pair and stays
319
+ // a leaf too; the source text is preserved either way.
320
+ out.push(twig);
321
+ continue;
322
+ }
293
323
  stack.push({ open: twig, sections: [{ head: null, body: [] }] });
294
324
  continue;
295
325
  }
@@ -0,0 +1 @@
1
+ {"adoption01.dat":["<a><p></a></p>","<a>1<p>2</a>3</p>","<a>1<button>2</a>3</button>","<a>1<b>2</a>3</b>","<a>1<div>2<div>3</a>4</div>5</div>","<table><a>1<p>2</a>3</p>","<b><b><a><p></a>","<b><a><b><p></a>","<a><b><b><p></a>","<p>1<s id=\"A\">2<b id=\"B\">3</p>4</s>5</b>","<table><a>1<td>2</td>3</table>","<table>A<td>B</td>C</table>","<a><svg><tr><input></a>","<div><a><b><div><div><div><div><div><div><div><div><div><div></a>","<div><a><b><u><i><code><div></a>","<b><b><b><b>x</b></b></b></b>y","<p><b><b><b><b><p>x","<b><em><foo><foob><fooc><aside></b></em>"],"adoption02.dat":["<b>1<i>2<p>3</b>4","<a><div><style></style><address><a>","<nobr><table><marquee></table><nobr>","<a><table><marquee></table><a>"],"blocks.dat":["<!doctype html><p>foo<address>bar<p>baz","<!doctype html><address><p>foo</address>bar","<!doctype html><p>foo<article>bar<p>baz","<!doctype html><article><p>foo</article>bar","<!doctype html><p>foo<aside>bar<p>baz","<!doctype html><aside><p>foo</aside>bar","<!doctype html><p>foo<blockquote>bar<p>baz","<!doctype html><blockquote><p>foo</blockquote>bar","<!doctype html><p>foo<center>bar<p>baz","<!doctype html><center><p>foo</center>bar","<!doctype html><p>foo<details>bar<p>baz","<!doctype html><details><p>foo</details>bar","<!doctype html><p>foo<dialog>bar<p>baz","<!doctype html><dialog><p>foo</dialog>bar","<!doctype html><p>foo<dir>bar<p>baz","<!doctype html><dir><p>foo</dir>bar","<!doctype html><p>foo<div>bar<p>baz","<!doctype html><div><p>foo</div>bar","<!doctype html><p>foo<dl>bar<p>baz","<!doctype html><dl><p>foo</dl>bar","<!doctype html><p>foo<fieldset>bar<p>baz","<!doctype html><fieldset><p>foo</fieldset>bar","<!doctype html><p>foo<figcaption>bar<p>baz","<!doctype html><figcaption><p>foo</figcaption>bar","<!doctype html><p>foo<figure>bar<p>baz","<!doctype html><figure><p>foo</figure>bar","<!doctype html><p>foo<footer>bar<p>baz","<!doctype html><footer><p>foo</footer>bar","<!doctype html><p>foo<header>bar<p>baz","<!doctype html><header><p>foo</header>bar","<!doctype html><p>foo<hgroup>bar<p>baz","<!doctype html><hgroup><p>foo</hgroup>bar","<!doctype html><p>foo<listing>bar<p>baz","<!doctype html><listing><p>foo</listing>bar","<!doctype html><p>foo<menu>bar<p>baz","<!doctype html><menu><p>foo</menu>bar","<!doctype html><p>foo<nav>bar<p>baz","<!doctype html><nav><p>foo</nav>bar","<!doctype html><p>foo<ol>bar<p>baz","<!doctype html><ol><p>foo</ol>bar","<!doctype html><p>foo<pre>bar<p>baz","<!doctype html><pre><p>foo</pre>bar","<!doctype html><p>foo<section>bar<p>baz","<!doctype html><section><p>foo</section>bar","<!doctype html><p>foo<summary>bar<p>baz","<!doctype html><summary><p>foo</summary>bar","<!doctype html><p>foo<ul>bar<p>baz","<!doctype html><ul><p>foo</ul>bar"],"comments01.dat":["FOO<!-- BAR -->BAZ","FOO<!-- BAR --!>BAZ","FOO<!-- BAR --! >BAZ","FOO<!-- BAR --!\n>BAZ","FOO<!-- BAR -- >BAZ","FOO<!-- BAR -- <QUX> -- MUX -->BAZ","FOO<!-- BAR -- <QUX> -- MUX --!>BAZ","FOO<!-- BAR -- <QUX> -- MUX -- >BAZ","FOO<!---->BAZ","FOO<!--->BAZ","FOO<!-->BAZ","<?xml version=\"1.0\">Hi","<?xml version=\"1.0\">","<?xml version","FOO<!----->BAZ","<html><!-- comment --><title>Comment before head</title>"],"doctype01.dat":["<!DOCTYPE html>Hello","<!dOctYpE HtMl>Hello","<!DOCTYPEhtml>Hello","<!DOCTYPE>Hello","<!DOCTYPE >Hello","<!DOCTYPE potato>Hello","<!DOCTYPE potato >Hello","<!DOCTYPE potato taco>Hello","<!DOCTYPE potato taco \"ddd>Hello","<!DOCTYPE potato sYstEM>Hello","<!DOCTYPE potato sYstEM >Hello","<!DOCTYPE potato sYstEM ggg>Hello","<!DOCTYPE potato SYSTEM taco >Hello","<!DOCTYPE potato SYSTEM 'taco\"'>Hello","<!DOCTYPE potato SYSTEM \"taco\">Hello","<!DOCTYPE potato SYSTEM \"tai'co\">Hello","<!DOCTYPE potato SYSTEMtaco \"ddd\">Hello","<!DOCTYPE potato grass SYSTEM taco>Hello","<!DOCTYPE potato pUbLIc>Hello","<!DOCTYPE potato pUbLIc >Hello","<!DOCTYPE potato pUbLIcgoof>Hello","<!DOCTYPE potato PUBLIC goof>Hello","<!DOCTYPE potato PUBLIC \"go'of\">Hello","<!DOCTYPE potato PUBLIC 'go'of'>Hello","<!DOCTYPE potato PUBLIC 'go:hh of' >Hello","<!DOCTYPE potato PUBLIC \"W3C-//dfdf\" SYSTEM ggg>Hello","<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n \"http://www.w3.org/TR/html4/strict.dtd\">Hello","<!DOCTYPE ...>Hello","<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">","<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">","<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] \"uri\" [ \n<!-- internal declarations -->\n]>","<!DOCTYPE html PUBLIC\n \"-//WAPFORUM//DTD XHTML Mobile 1.0//EN\"\n \"http://www.wapforum.org/DTD/xhtml-mobile10.dtd\">","<!DOCTYPE HTML SYSTEM \"http://www.w3.org/DTD/HTML4-strict.dtd\"><body><b>Mine!</b></body>","<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">","<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"'http://www.w3.org/TR/html4/strict.dtd'>","<!DOCTYPE HTML PUBLIC\"-//W3C//DTD HTML 4.01//EN\"'http://www.w3.org/TR/html4/strict.dtd'>","<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'>"],"domjs-unsafe.dat":["<svg><![CDATA[foo\nbar]]>","<svg><![CDATA[foo\rbar]]>","<svg><![CDATA[foo\r\nbar]]>","<script>a='\u0000'</script>","<script type=\"data\"><!--\u0000</script>","<script type=\"data\"><!--foo\u0000</script>","<script type=\"data\"><!-- foo-\u0000</script>","<script type=\"data\"><!-- foo--\u0000</script>","<script type=\"data\"><!-- foo-","<script type=\"data\"><!-- foo-<</script>","<script type=\"data\"><!-- foo-<S","<script type=\"data\"><!-- foo-</SCRIPT>","<script type=\"data\"><!--<p></script>","<script type=\"data\"><!--<script></script></script>","<script type=\"data\"><!--<script>\u0000</script></script>","<script type=\"data\"><!--<script>-\u0000</script></script>","<script type=\"data\"><!--<script>--\u0000</script></script>","<script type=\"data\"><!--<script>---</script></script>","<script type=\"data\"><!--<script></scrip></SCRIPT></script>","<script type=\"data\"><!--<script></scrip </SCRIPT></script>","<script type=\"data\"><!--<script></scrip/</SCRIPT></script>","<script type=\"data\"></scrip/></script>","<script type=\"data\"></scrip ></script>","<script type=\"data\"><!--</scrip></script>","<script type=\"data\"><!--</scrip </script>","<script type=\"data\"><!--</scrip/</script>","<!DOCTYPE html><!DOCTYPE html>","<html><!DOCTYPE html>","<html><head><!DOCTYPE html></head>","<html><head></head><!DOCTYPE html>","<body></body><!DOCTYPE html>","<table><!DOCTYPE html></table>","<select><!DOCTYPE html></select>","<table><colgroup><!DOCTYPE html></colgroup></table>","<table><colgroup><!--test--></colgroup></table>","<table><colgroup><html></colgroup></table>","<table><colgroup> foo</colgroup></table>","<select><!--test--></select>","<select><html></select>","<frameset><html></frameset>","<frameset></frameset><html>","<frameset></frameset><!DOCTYPE html>","<html><body></body></html><!DOCTYPE html>","<svg><!DOCTYPE html></svg>","<svg><font></font></svg>","<svg><font id=foo></font></svg>","<svg><font size=4></font></svg>","<svg><font color=red></font></svg>","<svg><font font=sans></font></svg>"],"entities01.dat":["FOO&gt;BAR","FOO&gtBAR","FOO&gt BAR","FOO&gt;;;BAR","I'm &notit; I tell you","I'm &notin; I tell you","&ammmp;","&ammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmp;","FOO& BAR","FOO&<BAR>","FOO&&&&gt;BAR","FOO&#41;BAR","FOO&#x41;BAR","FOO&#X41;BAR","FOO&#BAR","FOO&#ZOO","FOO&#xBAR","FOO&#xZOO","FOO&#XZOO","FOO&#41BAR","FOO&#x41BAR","FOO&#x41ZOO","FOO&#x0000;ZOO","FOO&#x0078;ZOO","FOO&#x0079;ZOO","FOO&#x0080;ZOO","FOO&#x0081;ZOO","FOO&#x0082;ZOO","FOO&#x0083;ZOO","FOO&#x0084;ZOO","FOO&#x0085;ZOO","FOO&#x0086;ZOO","FOO&#x0087;ZOO","FOO&#x0088;ZOO","FOO&#x0089;ZOO","FOO&#x008A;ZOO","FOO&#x008B;ZOO","FOO&#x008C;ZOO","FOO&#x008D;ZOO","FOO&#x008E;ZOO","FOO&#x008F;ZOO","FOO&#x0090;ZOO","FOO&#x0091;ZOO","FOO&#x0092;ZOO","FOO&#x0093;ZOO","FOO&#x0094;ZOO","FOO&#x0095;ZOO","FOO&#x0096;ZOO","FOO&#x0097;ZOO","FOO&#x0098;ZOO","FOO&#x0099;ZOO","FOO&#x009A;ZOO","FOO&#x009B;ZOO","FOO&#x009C;ZOO","FOO&#x009D;ZOO","FOO&#x009E;ZOO","FOO&#x009F;ZOO","FOO&#x00A0;ZOO","FOO&#xD7FF;ZOO","FOO&#xD800;ZOO","FOO&#xD801;ZOO","FOO&#xDFFE;ZOO","FOO&#xDFFF;ZOO","FOO&#xE000;ZOO","FOO&#x10FFFE;ZOO","FOO&#x1087D4;ZOO","FOO&#x10FFFF;ZOO","FOO&#x110000;ZOO","FOO&#xFFFFFF;ZOO","FOO&#11111111111","FOO&#1111111111","FOO&#111111111111","FOO&#11111111111ZOO","FOO&#1111111111ZOO","FOO&#111111111111ZOO"],"entities02.dat":["<div bar=\"ZZ&gt;YY\"></div>","<div bar=\"ZZ&\"></div>","<div bar='ZZ&'></div>","<div bar=ZZ&></div>","<div bar=\"ZZ&gt=YY\"></div>","<div bar=\"ZZ&gt0YY\"></div>","<div bar=\"ZZ&gt9YY\"></div>","<div bar=\"ZZ&gtaYY\"></div>","<div bar=\"ZZ&gtZYY\"></div>","<div bar=\"ZZ&gt YY\"></div>","<div bar=\"ZZ&gt\"></div>","<div bar='ZZ&gt'></div>","<div bar=ZZ&gt></div>","<div bar=\"ZZ&pound_id=23\"></div>","<div bar=\"ZZ&prod_id=23\"></div>","<div bar=\"ZZ&pound;_id=23\"></div>","<div bar=\"ZZ&prod;_id=23\"></div>","<div bar=\"ZZ&pound=23\"></div>","<div bar=\"ZZ&prod=23\"></div>","<div>ZZ&pound_id=23</div>","<div>ZZ&prod_id=23</div>","<div>ZZ&pound;_id=23</div>","<div>ZZ&prod;_id=23</div>","<div>ZZ&pound=23</div>","<div>ZZ&prod=23</div>","<div>ZZ&AElig=</div>"],"foreign-fragment.dat":["<nobr>X","<font color></font>X","<font></font>X","<g></path>X","</path>X","</foreignObject>X","</desc>X","</title>X","</svg>X","</mfenced>X","</malignmark>X","</math>X","</annotation-xml>X","</mtext>X","</mi>X","</mo>X","</mn>X","</ms>X","<b></b><mglyph/><i></i><malignmark/><u></u><ms/>X","<malignmark></malignmark>","<div></div>","<figure></figure>","<b></b><mglyph/><i></i><malignmark/><u></u><mn/>X","<malignmark></malignmark>","<div></div>","<figure></figure>","<b></b><mglyph/><i></i><malignmark/><u></u><mo/>X","<malignmark></malignmark>","<div></div>","<figure></figure>","<b></b><mglyph/><i></i><malignmark/><u></u><mi/>X","<malignmark></malignmark>","<div></div>","<figure></figure>","<b></b><mglyph/><i></i><malignmark/><u></u><mtext/>X","<malignmark></malignmark>","<div></div>","<figure></figure>","<div></div>","<figure></figure>","<div></div>","<figure></figure>","<div></div>","<figure></figure>","<div></div>","<figure></figure>","<figure></figure>","<div><h1>X</h1></div>","<div></div>","<div></div>","<plaintext><foo>","<frameset>X","<head>X","<body>X","<html>X","<html class=\"foo\">X","<body class=\"foo\">X","<svg><p>","<p>","<svg></p><foo>","<svg></br><foo>","</p><foo>","</br><foo>","<body><foo>","<p><foo>","<p></p><foo>"],"html5test-com.dat":["<div<div>","<div foo<bar=''>","<div foo=`bar`>","<div \\\"foo=''>","<a href='\\nbar'></a>","<!DOCTYPE html>","&lang;&rang;","&apos;","&ImaginaryI;","&Kopf;","&notinva;","<?import namespace=\"foo\" implementation=\"#bar\">","<!--foo--bar-->","<svg><title><![CDATA[x]]>","<svg><foreignobject><![CDATA[x]]>","<svg><foreignobject><p><![CDATA[x]]>","<math><![CDATA[x]]>","<math><mtext><![CDATA[x]]>","<math><mtext><i><![CDATA[x]]>","<![CDATA[x]]>","<textarea><!--</textarea>--></textarea>","<textarea><!--</textarea>-->","<style><!--</style>--></style>","<style><!--</style>-->","<ul><li>A </li> <li>B</li></ul>","<table><form><input type=hidden><input></form><div></div></table>","<i>A<b>B<p></i>C</b>D","<div></div>","<svg></svg>","<math></math>"],"inbody01.dat":["<button>1</foo>","<foo>1<p>2</foo>","<dd>1</foo>","<foo>1<dd>2</foo>"],"isindex.dat":["<isindex>","<isindex name=\"A\" action=\"B\" prompt=\"C\" foo=\"D\">","<form><isindex>","<!doctype html><isindex>x</isindex>x"],"main-element.dat":["<!doctype html><p>foo<main>bar<p>baz","<!doctype html><main><p>foo</main>bar","<!DOCTYPE html>xxx<svg><x><g><a><main><b>"],"math.dat":["<math><tr><td><mo><tr>","<math><tr><td><mo><tr>","<math><thead><mo><tbody>","<math><tfoot><mo><tbody>","<math><tbody><mo><tfoot>","<math><tbody><mo></table>","<math><thead><mo></table>","<math><tfoot><mo></table>"],"menuitem-element.dat":["<menuitem>","</menuitem>","<!DOCTYPE html><body><menuitem>A","<!DOCTYPE html><body><menuitem>A<menuitem>B","<!DOCTYPE html><body><menuitem>A<menu>B</menu>","<!DOCTYPE html><body><menuitem>A<hr>B","<!DOCTYPE html><li><menuitem><li>","<!DOCTYPE html><menuitem><p></menuitem>x","<!DOCTYPE html><p><b></p><menuitem>","<!DOCTYPE html><menuitem><asdf></menuitem>x","<!DOCTYPE html></menuitem>","<!DOCTYPE html><html></menuitem>","<!DOCTYPE html><head></menuitem>","<!DOCTYPE html><select><menuitem></select>","<!DOCTYPE html><option><menuitem>","<!DOCTYPE html><menuitem><option>","<!DOCTYPE html><menuitem></body>","<!DOCTYPE html><menuitem></html>","<!DOCTYPE html><menuitem><p>","<!DOCTYPE html><menuitem><li>"],"namespace-sensitivity.dat":["<body><table><tr><td><svg><td><foreignObject><span></td>Foo"],"noscript01.dat":["<head><noscript><!doctype html><!--foo--></noscript>","<head><noscript><html class=\"foo\"><!--foo--></noscript>","<head><noscript></noscript>","<head><noscript> </noscript>","<head><noscript><!--foo--></noscript>","<head><noscript><basefont><!--foo--></noscript>","<head><noscript><bgsound><!--foo--></noscript>","<head><noscript><link><!--foo--></noscript>","<head><noscript><meta><!--foo--></noscript>","<head><noscript><noframes>XXX</noscript></noframes></noscript>","<head><noscript><style>XXX</style></noscript>","<head><noscript></br><!--foo--></noscript>","<head><noscript><head class=\"foo\"><!--foo--></noscript>","<head><noscript><noscript class=\"foo\"><!--foo--></noscript>","<head><noscript></p><!--foo--></noscript>","<head><noscript><p><!--foo--></noscript>","<head><noscript>XXX<!--foo--></noscript></head>","<head><noscript>"],"pending-spec-changes-plain-text-unsafe.dat":["<body><table>\u0000filler\u0000text\u0000"],"pending-spec-changes.dat":["<input type=\"hidden\"><frameset>","<!DOCTYPE html><table><caption><svg>foo</table>bar","<table><tr><td><svg><desc><td></desc><circle>"],"plain-text-unsafe.dat":["FOO&#x000D;ZOO","<html>\u0000<frameset></frameset>","<html> \u0000 <frameset></frameset>","<html>a\u0000a<frameset></frameset>","<html>\u0000\u0000<frameset></frameset>","<html>\u0000\n<frameset></frameset>","<html><select>\u0000","\u0000","<body>\u0000","<plaintext>\u0000filler\u0000text\u0000","<svg><![CDATA[\u0000filler\u0000text\u0000]]>","<body><!\u0000>","<body><!\u0000filler\u0000text>","<body><svg><foreignObject>\u0000filler\u0000text","<svg>\u0000filler\u0000text","<svg>\u0000<frameset>","<svg>\u0000 <frameset>","<svg>\u0000a<frameset>","<svg>\u0000</svg><frameset>","<svg>\u0000 </svg><frameset>","<svg>\u0000a</svg><frameset>","<svg><path></path></svg><frameset>","<svg><p><frameset>","<!DOCTYPE html><pre>\r\n\r\nA</pre>","<!DOCTYPE html><pre>\r\rA</pre>","<!DOCTYPE html><pre>\rA</pre>","<!DOCTYPE html><table><tr><td><math><mtext>\u0000a","<!DOCTYPE html><table><tr><td><svg><foreignObject>\u0000a","<!DOCTYPE html><math><mi>a\u0000b","<!DOCTYPE html><math><mo>a\u0000b","<!DOCTYPE html><math><mn>a\u0000b","<!DOCTYPE html><math><ms>a\u0000b","<!DOCTYPE html><math><mtext>a\u0000b","<math>\u0000filler\u0000text","<math><![CDATA[\u0000filler\u0000text\u0000]]>","<math><annotation-xml>\u0000x","<math><annotation-xml encoding=\"text/html\">\u0000x","\u0000filler\u0000text","\u0000filler\u0000text","\u0000filler\u0000text","\u0000x","\u0000filler\u0000text","\u0000filler\u0000text","\u0000filler\u0000text","\u0000filler\u0000text","\u0000filler\u0000text","\u0000filler\u0000text","\u0000filler\u0000text"],"processing-instructions.dat":["<body><?something>","<body><?something><span>","<body><?something good>","<body><?something else is good>","<body><?one><?two>","<body><?a$><?b$><?good?>","<body><?hey there?>","<body><?hey there?>","<body><?hey?there>","<body><?hey\tthere=1?>","<body><?hey\nthere=1?>","<body><?hey\rthere=1?>","<body><?hey\fthere=1?>","<body><?something ? >","<body><?something x >","<body><?something ?\\t ??>","<body><?t d > ?>","<body><?module-handler>","<body><?module-handler data>","<body><?view-port>","<body><?view-port data>","<body><?config-v2>","<body><?config-v2 data>","<body><?x>","<body><?x data>","<body><?zz2op>","<body><?zz2op data>","<body><?xla->","<body><?xla- data>","<body><?a-b-c>","<body><?a-b-c data>","<body><?v-123>","<body><?v-123 data>","<body><?a0-b1-c2>","<body><?a0-b1-c2 data>","<body><?page-404>","<body><?page-404 data>","<body><?r2-d2>","<body><?r2-d2 data>","<body><?level-99>","<body><?level-99 data>","<body><?UPPERCASE>","<body><?UPPERCASE data>","<body><?all-KINDS-of-CaSeS>","<body><?all-KINDS-of-CaSeS data>","<body><?user_name>","<body><?user_name data>","<body><?S_S-S_S>","<body><?S_S-S_S data>","<body><?b_>","<body><?b_ data>","<body><?_prefix>","<body><?_prefix data>","<body><?_x132>","<body><?_x132 data>","<body><?_-_>","<body><?_-_ data>","<body><?_>","<body><?_ data>","<body><?A---------------->","<body><?A---------------- data>","<body><?z0123456789>","<body><?z0123456789 data>","<body><?m-0>","<body><?m-0 data>","<body><?xml>","<body><?xml-stylesheet>","<body><?XML>","<body><?XML-stylesheet>","<body><?xML>","<body><?xml-STYLesheet>","<body><?1st-place>","<body><?2-factor>","<body><?99-problems>","<body><?٥-star>","<body><?-prefix>","<body><?--internal>","<body><?-data->","<body><?-100>","<body><?·middle-dot>","<body><?͵greek-numeral>","<body><?́accent-start>","<body><?price$value>","<body><?user@domain>","<body><?tag#id>","<body><?a+b>","<body><?100%>","<body><?data.v1>","<body><?namespace:tag>","<body><?error!code>","<body><?x=y>","<body><?a<b>","<body><?true&false>","<body><?not|or>","<body><?lit$123456789>","<body><?lit$$4x>","<body><?🚀-launch>","<body><?error-⚠️>","<body><?fire-🔥>","<body><?v1-✅>","<body><?start","<body><?start?","<body><?start ","<body><?start data","<body><?start ? ?","<body><?","<body><? ","<div><?something></div>","<div><?something good></div>","<table><?something></table>","<table><tr><?something></tr></table>","<script><?something></script>","<style><?something></style>","<?something>","<head><?something>","<html><?something><head>","<html><head></head><?something><body>","<html><body></body><?something>","<html><body></body></html><?something>","<body><template><?something></template>","<body><textarea><?something></textarea>","<body><title><?something></title>","<noscript><?pi>","<template><?pi>"],"quirks01.dat":["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\"><p><table>","<!DOCTYPE html SYSTEM \"http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd\"><p><table>","<!DOCTYPE html PUBLIC \"html\"><p><table>","<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"\n \"http://www.w3.org/TR/html4/strict.dtd\"><p><table>"],"ruby.dat":["<html><ruby>a<rb>b<rb></ruby></html>","<html><ruby>a<rb>b<rt></ruby></html>","<html><ruby>a<rb>b<rtc></ruby></html>","<html><ruby>a<rb>b<rp></ruby></html>","<html><ruby>a<rb>b<span></ruby></html>","<html><ruby>a<rt>b<rb></ruby></html>","<html><ruby>a<rt>b<rt></ruby></html>","<html><ruby>a<rt>b<rtc></ruby></html>","<html><ruby>a<rt>b<rp></ruby></html>","<html><ruby>a<rt>b<span></ruby></html>","<html><ruby>a<rtc>b<rb></ruby></html>","<html><ruby>a<rtc>b<rt>c<rt>d</ruby></html>","<html><ruby>a<rtc>b<rtc></ruby></html>","<html><ruby>a<rtc>b<rp></ruby></html>","<html><ruby>a<rtc>b<span></ruby></html>","<html><ruby>a<rp>b<rb></ruby></html>","<html><ruby>a<rp>b<rt></ruby></html>","<html><ruby>a<rp>b<rtc></ruby></html>","<html><ruby>a<rp>b<rp></ruby></html>","<html><ruby>a<rp>b<span></ruby></html>","<html><ruby><rtc><ruby>a<rb>b<rt></ruby></ruby></html>"],"scriptdata01.dat":["FOO<script>'Hello'</script>BAR","FOO<script></script>BAR","FOO<script></script >BAR","FOO<script></script/>BAR","FOO<script></script/ >BAR","FOO<script type=\"text/plain\"></scriptx>BAR","FOO<script></script foo=\">\" dd>BAR","FOO<script>'<'</script>BAR","FOO<script>'<!'</script>BAR","FOO<script>'<!-'</script>BAR","FOO<script>'<!--'</script>BAR","FOO<script>'<!---'</script>BAR","FOO<script>'<!-->'</script>BAR","FOO<script>'<!-- potato'</script>BAR","FOO<script>'<!-- <sCrIpt'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt>'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt> -'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt> --'</script>BAR","FOO<script>'<!-- <sCrIpt> -->'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt> --!>'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt> -- >'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt '</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt/'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt\\'</script>BAR","FOO<script type=\"text/plain\">'<!-- <sCrIpt/'</script>BAR</script>QUX","FOO<script><!--<script>-></script>--></script>QUX"],"scripted_adoption01.dat":["<p><b id=\"A\"><script>document.getElementById(\"A\").id = \"B\"</script></p>TEXT</b>"],"scripted_ark.dat":["<p><font size=4><font size=4><font size=4><script>document.getElementsByTagName(\"font\")[2].setAttribute(\"size\", \"5\");</script><font size=4><p>X"],"scripted_foster01.dat":["<table><tr><script>var t=document.querySelector('table');document.documentElement.remove();document.appendChild(t)</script><b>","<table><tr><script>var t=document.querySelector('table');document.documentElement.remove();document.appendChild(t)</script>FOSTERTEXT"],"scripted_webkit01.dat":["1<script>document.write(\"2\")</script>3","1<script>document.write(\"<script>document.write('2')</scr\"+ \"ipt><script>document.write('3')</scr\" + \"ipt>\")</script>4"],"search-element.dat":["<!doctype html><p>foo<search>bar<p>baz","<!doctype html><search><p>foo</search>bar","<!DOCTYPE html>xxx<svg><x><g><a><search><b>"],"svg.dat":["<svg><tr><td><title><tr>","<svg><tr><td><title><tr>","<svg><thead><title><tbody>","<svg><tfoot><title><tbody>","<svg><tbody><title><tfoot>","<svg><tbody><title></table>","<svg><thead><title></table>","<svg><tfoot><title></table>"],"tables01.dat":["<table><th>","<table><td>","<table><col foo='bar'>","<table><colgroup></html>foo","<table></table><p>foo","<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td>","<table><select><option>3</select></table>","<table><select><table></table></select></table>","<table><select></table>","<table><select><option>A<tr><td>B</td></tr></table>","<table><td></body></caption></col></colgroup></html>foo","<table><td>A</table>B","<table><tr><caption>","<table><tr></body></caption></col></colgroup></html></td></th><td>foo","<table><td><tr>","<table><td><button><td>","<table><tr><td><svg><desc><td>","<div><table><svg><foreignObject><select><table><s>","<table>a<!doctype html>"],"template.dat":["<body><template>Hello</template>","<template>Hello</template>","<template></template><div></div>","<html><template>Hello</template>","<head><template><div></div></template></head>","<div><template><div><span></template><b>","<div><template></div>Hello","<div></template></div>","<table><template></template></table>","<table><template></template></div>","<table><div><template></template></div>","<table><template></template><div></div>","<table> <template></template></table>","<table><tbody><template></template></tbody>","<table><tbody><template></tbody></template>","<table><tbody><template></template></tbody></table>","<table><thead><template></template></thead>","<table><tfoot><template></template></tfoot>","<select><template></template></select>","<select><template><option></option></template></select>","<template><option></option></select><option></option></template>","<select><template></template><option></select>","<select><option><template></template></select>","<select><template>","<select><option></option><template>","<select><option></option><template><option>","<table><thead><template><td></template></table>","<table><template><thead></template></table>","<body><table><template><td></tr><div></template></table>","<table><template><thead></template></thead></table>","<table><thead><template><tr></template></table>","<table><template><tr></template></table>","<table><tr><template><td>","<table><template><tr><template><td></template></tr></template></table>","<table><template><tr><template><td></td></template></tr></template></table>","<table><template><td></template>","<body><template><td></td></template>","<body><template><template><tr></tr></template><td></td></template>","<table><colgroup><template><col>","<frameset><template><frame></frame></template></frameset>","<template><frame></frame></frameset><frame></frame></template>","<template><div><frameset><span></span></div><span></span></template>","<body><template><div><frameset><span></span></div><span></span></template></body>","<head><template></template></head><p><frameset>","<template>x</template><p><frameset>","<head></head><template></template><p><frameset>","<p><template></template><frameset>","<p><template><frameset></template>","<template></template>x<frameset>","<body><template><script>var i = 1;</script><td></td></template>","<body><template><tr><div></div></tr></template>","<table><template><tr><div></div></tr></template>","<body><template><tr></tr><td></td></template>","<body><template><td></td></tr><td></td></template>","<body><template><td></td><tbody><td></td></template>","<body><template><td></td><caption></caption><td></td></template>","<body><template><td></td><colgroup></caption><td></td></template>","<body><template><td></td></table><td></td></template>","<body><template><tr></tr><tbody><tr></tr></template>","<body><template><tr></tr><caption><tr></tr></template>","<body><template><tr></tr></table><tr></tr></template>","<body><template><thead></thead><caption></caption><tbody></tbody></template>","<body><template><thead></thead></table><tbody></tbody></template></body>","<body><template><div><tr></tr></div></template>","<body><template><em>Hello</em></template>","<body><template><!--comment--></template>","<body><template><style></style><td></td></template>","<body><template><meta><td></td></template>","<body><template><link><td></td></template>","<body><table><colgroup><template><col></col></template></colgroup></table></body>","<body a=b><template><div></div><body c=d><div></div></body></template></body>","<html a=b><template><div><html b=c><span></template>","<html a=b><template><col></col><html b=c><col></col></template>","<html a=b><template><frame></frame><html b=c><frame></frame></template>","<body><template><tr></tr><template></template><td></td></template>","<body><template><thead></thead><template><tr></tr></template><tr></tr><tfoot></tfoot></template>","<body><template><template><b><template></template></template>text</template>","<body><template><col><colgroup>","<body><template><col></colgroup>","<body><template><col><colgroup></template></body>","<body><template><col><div>","<body><template><col></div>","<body><template><col>Hello","<body><template><i><menu>Foo</i>","<body><template></div><div>Foo</div><template></template><tr></tr>","<body><div><template></div><tr><td>Foo</td></tr></template>","<template></figcaption><sub><table></table>","<template><template>","<template><div>","<template><template><div>","<template><template><table>","<template><template><tbody>","<template><template><tr>","<template><template><td>","<template><template><caption>","<template><template><colgroup>","<template><template><col>","<template><template><tbody><select>","<template><template><table>Foo","<template><template><frame>","<template><template><script>var i","<template><template><style>var i","<template><table></template><body><span>Foo","<template><td></template><body><span>Foo","<template><object></template><body><span>Foo","<template><svg><template>","<template><svg><foo><template><foreignObject><div></template><div>","<dummy><template><span></dummy>","<body><table><tr><td><select><template>Foo</template><caption>A</table>","<body></body><template>","<head></head><template>","<head></head><template>Foo</template>","<html><head></head><template></template><head>","<!DOCTYPE HTML><dummy><table><template><table><template><table><script>","<template><a><table><a>","<template><form><input name=\"q\"></form><div>second</div></template>","<template><table><form></table></template>","<table><form></table>","<template><form><form><input></template>","<form><form>","<template><form><template></template><form></template>","<template><template><form></template><form></template>","<form><template><form></template><form>","<br>BC<form>D<div>E</form>F</div>G","<!DOCTYPE HTML><template><tr><td>cell</td></tr></template>","<!DOCTYPE HTML><template> <tr> <td>cell</td> </tr> </template>","<!DOCTYPE HTML><template><tr><td>cell</td></tr>a</template>"],"tests1.dat":["Test","<p>One<p>Two","Line1<br>Line2<br>Line3<br>Line4","<html>","<head>","<body>","<html><head>","<html><head></head>","<html><head></head><body>","<html><head></head><body></body>","<html><head><body></body></html>","<html><head></body></html>","<html><head><body></html>","<html><body></html>","<body></html>","<head></html>","</head>","</body>","</html>","<b><table><td><i></table>","<b><table><td></b><i></table>X","<h1>Hello<h2>World","<a><p>X<a>Y</a>Z</p></a>","<b><button>foo</b>bar","<!DOCTYPE html><span><button>foo</span>bar","<p><b><div><marquee></p></b></div>X","<script><div></script></div><title><p></title><p><p>","<!--><div>--<!-->","<p><hr></p>","<select><b><option><select><option></b></select>X","<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y","<a X>0<b>1<a Y>2","<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->","<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->","<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E","<","<#","</","</#","<?","<?#","<!","<!#","<?COMMENT?>","<!COMMENT>","</ COMMENT >","<?COM--MENT?>","<!COM--MENT>","</ COM--MENT >","<!DOCTYPE html><style> EOF","<!DOCTYPE html><script> <!-- </script> --> </script> EOF","<b><p></b>TEST","<p id=a><b><p id=b></b>TEST","<b id=a><p><b id=b></p></b>TEST","<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>","<!DOCTYPE html><font><table></font></table></font>","<font><p>hello<b>cruel</font>world","<b>Test</i>Test","<b>A<cite>B<div>C","<b>A<cite>B<div>C</cite>D","<b>A<cite>B<div>C</b>D","","<DIV>","<DIV> abc","<DIV> abc <B>","<DIV> abc <B> def","<DIV> abc <B> def <I>","<DIV> abc <B> def <I> ghi","<DIV> abc <B> def <I> ghi <P>","<DIV> abc <B> def <I> ghi <P> jkl","<DIV> abc <B> def <I> ghi <P> jkl </B>","<DIV> abc <B> def <I> ghi <P> jkl </B> mno","<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>","<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr","<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>","<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu","<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->","<a href=\"blah\">aba<table><a href=\"foo\">br<tr><td></td></tr>x</table>aoe","<a href=\"blah\">aba<table><tr><td><a href=\"foo\">br</td></tr>x</table>aoe","<table><a href=\"blah\">aba<tr><td><a href=\"foo\">br</td></tr>x</table>aoe","<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa","<wbr><strike><code></strike><code><strike></code>","<!DOCTYPE html><spacer>foo","<title><meta></title><link><title><meta></title>","<style><!--</style><meta><script>--><link></script>","<head><meta></head><link>","<table><tr><tr><td><td><span><th><span>X</table>","<body><body><base><link><meta><title><p></title><body><p></body>","<textarea><p></textarea>","<p><image></p>","<a><table><a></table><p><a><div><a>","<head></p><meta><p>","<head></html><meta><p>","<b><table><td></b><i></table>","<h1><h2>","<a><p><a></a></p></a>","<b><button></b></button></b>","<p><b><div><marquee></p></b></div>","<script></script></div><title></title><p><p>","<select><b><option><select><option></b></select>","<html><head><title></title><body></body></html>","<a><table><td><a><table></table><a></tr><a></table><a>","<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>","<ul><li><ul></li><li>a</li></ul></li></ul>","<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>","<h1><table><td><h3></table><h3></h1>","<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>","<table><col><tbody><col><tr><col><td><col></table><col>","<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>","</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>","<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>","<frameset>"],"tests10.dat":["<!DOCTYPE html><svg></svg>","<!DOCTYPE html><svg></svg><![CDATA[a]]>","<!DOCTYPE html><body><svg></svg>","<!DOCTYPE html><body><select><svg></svg></select>","<!DOCTYPE html><body><select><option><svg></svg></option></select>","<!DOCTYPE html><body><table><svg></svg></table>","<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>","<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>","<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>","<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>","<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>","<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>","<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>","<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux","<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux","<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux","<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux","<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux","<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz","<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz","<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>","<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>","<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>","<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>","<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>","<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>","<svg></path>","<div><svg></div>a","<div><svg><path></div>a","<div><svg><path></svg><path>","<div><svg><path><foreignObject><math></div>a","<div><svg><path><foreignObject><p></div>a","<!DOCTYPE html><svg><desc><div><svg><ul>a","<!DOCTYPE html><svg><desc><svg><ul>a","<!DOCTYPE html><p><svg><desc><p>","<!DOCTYPE html><p><svg><title><p>","<div><svg><path><foreignObject><p></foreignObject><p>","<math><mi><div><object><div><span></span></div></object></div></mi><mi>","<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>","<svg><script></script><path>","<table><svg></svg><tr>","<math><mi><mglyph>","<math><mi><malignmark>","<math><mo><mglyph>","<math><mo><malignmark>","<math><mn><mglyph>","<math><mn><malignmark>","<math><ms><mglyph>","<math><ms><malignmark>","<math><mtext><mglyph>","<math><mtext><malignmark>","<math><annotation-xml><svg></svg></annotation-xml><mi>","<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi>","<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi>"],"tests11.dat":["<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' diffuseConstant='' edgeMode='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg>","<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' DIFFUSECONSTANT='' EDGEMODE='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG>","<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' diffuseconstant='' edgemode='' filterunits='' filterres='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg>","<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' diffuseConstant='' edgeMode='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math>","<!DOCTYPE html><body><svg contentScriptType='' contentStyleType='' externalResourcesRequired='' filterRes=''></svg>","<!DOCTYPE html><body><svg CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' EXTERNALRESOURCESREQUIRED='' FILTERRES=''></svg>","<!DOCTYPE html><body><svg contentscripttype='' contentstyletype='' externalresourcesrequired='' filterres=''></svg>","<!DOCTYPE html><body><math contentScriptType='' contentStyleType='' externalResourcesRequired='' filterRes=''></math>","<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg>","<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg>","<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG>","<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math>","<!DOCTYPE html><body><svg><solidColor /></svg>"],"tests12.dat":["<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar","<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar"],"tests14.dat":["<!DOCTYPE html><html><body><xyz:abc></xyz:abc>","<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>","<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>","<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>","<!DOCTYPE html><html 123=456>","<!DOCTYPE html><html 123=456><html 789=012>","<!DOCTYPE html><html><body 789=012>"],"tests15.dat":["<!DOCTYPE html><p><b><i><u></p> <p>X","<p><b><i><u></p>\n<p>X","<!doctype html></html> <head>","<!doctype html></body><meta>","<html></html><!-- foo -->","<!doctype html></body><title>X</title>","<!doctype html><table> X<meta></table>","<!doctype html><table> x</table>","<!doctype html><table> x </table>","<!doctype html><table><tr> x</table>","<!doctype html><table>X<style> <tr>x </style> </table>","<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>","<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>","<!DOCTYPE html><object></html>"],"tests16.dat":["<!doctype html><script>","<!doctype html><script>a","<!doctype html><script><","<!doctype html><script></","<!doctype html><script></S","<!doctype html><script></SC","<!doctype html><script></SCR","<!doctype html><script></SCRI","<!doctype html><script></SCRIP","<!doctype html><script></SCRIPT","<!doctype html><script></SCRIPT ","<!doctype html><script></s","<!doctype html><script></sc","<!doctype html><script></scr","<!doctype html><script></scri","<!doctype html><script></scrip","<!doctype html><script></script","<!doctype html><script></script ","<!doctype html><script><!","<!doctype html><script><!a","<!doctype html><script><!-","<!doctype html><script><!-a","<!doctype html><script><!--","<!doctype html><script><!--a","<!doctype html><script><!--<","<!doctype html><script><!--<a","<!doctype html><script><!--</","<!doctype html><script><!--</script","<!doctype html><script><!--</script ","<!doctype html><script><!--<s","<!doctype html><script><!--<script","<!doctype html><script><!--<script ","<!doctype html><script><!--<script <","<!doctype html><script><!--<script <a","<!doctype html><script><!--<script </","<!doctype html><script><!--<script </s","<!doctype html><script><!--<script </script","<!doctype html><script><!--<script </scripta","<!doctype html><script><!--<script </script ","<!doctype html><script><!--<script </script>","<!doctype html><script><!--<script </script/","<!doctype html><script><!--<script </script <","<!doctype html><script><!--<script </script <a","<!doctype html><script><!--<script </script </","<!doctype html><script><!--<script </script </script","<!doctype html><script><!--<script </script </script ","<!doctype html><script><!--<script </script </script/","<!doctype html><script><!--<script </script </script>","<!doctype html><script><!--<script -","<!doctype html><script><!--<script -a","<!doctype html><script><!--<script -<","<!doctype html><script><!--<script --","<!doctype html><script><!--<script --a","<!doctype html><script><!--<script --<","<!doctype html><script><!--<script -->","<!doctype html><script><!--<script --><","<!doctype html><script><!--<script --></","<!doctype html><script><!--<script --></script","<!doctype html><script><!--<script --></script ","<!doctype html><script><!--<script --></script/","<!doctype html><script><!--<script --></script>","<!doctype html><script><!--<script><\\/script>--></script>","<!doctype html><script><!--<script></scr'+'ipt>--></script>","<!doctype html><script><!--<script></script><script></script></script>","<!doctype html><script><!--<script></script><script></script>--><!--</script>","<!doctype html><script><!--<script></script><script></script>-- ></script>","<!doctype html><script><!--<script></script><script></script>- -></script>","<!doctype html><script><!--<script></script><script></script>- - ></script>","<!doctype html><script><!--<script></script><script></script>-></script>","<!doctype html><script><!--<script>--!></script>X","<!doctype html><script><!--<scr'+'ipt></script>--></script>","<!doctype html><script><!--<script></scr'+'ipt></script>X","<!doctype html><style><!--<style></style>--></style>","<!doctype html><style><!--</style>X","<!doctype html><style><!--...</style>...--></style>","<!doctype html><style><!--<br><html xmlns:v=\"urn:schemas-microsoft-com:vml\"><!--[if !mso]><style></style>X","<!doctype html><style><!--...<style><!--...--!></style>--></style>","<!doctype html><style><!--...</style><!-- --><style>@import ...</style>","<!doctype html><style>...<style><!--...</style><!-- --></style>","<!doctype html><style>...<!--[if IE]><style>...</style>X","<!doctype html><title><!--<title></title>--></title>","<!doctype html><title>&lt;/title></title>","<!doctype html><title>foo/title><link></head><body>X","<!doctype html><noscript><!--<noscript></noscript>--></noscript>","<!doctype html><noscript><!--<noscript></noscript>--></noscript>","<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>","<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>","<!doctype html><noscript><iframe></noscript>X","<!doctype html><noscript><iframe></noscript>X","<!doctype html><noframes><!--<noframes></noframes>--></noframes>","<!doctype html><noframes><body><script><!--...</script></body></noframes></html>","<!doctype html><textarea><!--<textarea></textarea>--></textarea>","<!doctype html><textarea>&lt;/textarea></textarea>","<!doctype html><textarea>&lt;</textarea>","<!doctype html><textarea>a&lt;b</textarea>","<!doctype html><iframe><!--<iframe></iframe>--></iframe>","<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>","<!doctype html><xmp><!--<xmp></xmp>--></xmp>","<!doctype html><noembed><!--<noembed></noembed>--></noembed>","<script>","<script>a","<script><","<script></","<script></S","<script></SC","<script></SCR","<script></SCRI","<script></SCRIP","<script></SCRIPT","<script></SCRIPT ","<script></s","<script></sc","<script></scr","<script></scri","<script></scrip","<script></script","<script></script ","<script><!","<script><!a","<script><!-","<script><!-a","<script><!--","<script><!--a","<script><!--<","<script><!--<a","<script><!--</","<script><!--</script","<script><!--</script ","<script><!--<s","<script><!--<script","<script><!--<script ","<script><!--<script <","<script><!--<script <a","<script><!--<script </","<script><!--<script </s","<script><!--<script </script","<script><!--<script </scripta","<script><!--<script </script ","<script><!--<script </script>","<script><!--<script </script/","<script><!--<script </script <","<script><!--<script </script <a","<script><!--<script </script </","<script><!--<script </script </script","<script><!--<script </script </script ","<script><!--<script </script </script/","<script><!--<script </script </script>","<script><!--<script -","<script><!--<script -a","<script><!--<script --","<script><!--<script --a","<script><!--<script -->","<script><!--<script --><","<script><!--<script --></","<script><!--<script --></script","<script><!--<script --></script ","<script><!--<script --></script/","<script><!--<script --></script>","<script><!--<script><\\/script>--></script>","<script><!--<script></scr'+'ipt>--></script>","<script><!--<script></script><script></script></script>","<script><!--<script></script><script></script>--><!--</script>","<script><!--<script></script><script></script>-- ></script>","<script><!--<script></script><script></script>- -></script>","<script><!--<script></script><script></script>- - ></script>","<script><!--<script></script><script></script>-></script>","<script><!--<script>--!></script>X","<script><!--<scr'+'ipt></script>--></script>","<script><!--<script></scr'+'ipt></script>X","<style><!--<style></style>--></style>","<style><!--</style>X","<style><!--...</style>...--></style>","<style><!--<br><html xmlns:v=\"urn:schemas-microsoft-com:vml\"><!--[if !mso]><style></style>X","<style><!--...<style><!--...--!></style>--></style>","<style><!--...</style><!-- --><style>@import ...</style>","<style>...<style><!--...</style><!-- --></style>","<style>...<!--[if IE]><style>...</style>X","<title><!--<title></title>--></title>","<title>&lt;/title></title>","<title>foo/title><link></head><body>X","<noscript><!--<noscript></noscript>--></noscript>","<noscript><!--<noscript></noscript>--></noscript>","<noscript><!--</noscript>X<noscript>--></noscript>","<noscript><!--</noscript>X<noscript>--></noscript>","<noscript><iframe></noscript>X","<noscript><iframe></noscript>X","<noframes><!--<noframes></noframes>--></noframes>","<noframes><body><script><!--...</script></body></noframes></html>","<textarea><!--<textarea></textarea>--></textarea>","<textarea>&lt;/textarea></textarea>","<iframe><!--<iframe></iframe>--></iframe>","<iframe>...<!--X->...<!--/X->...</iframe>","<xmp><!--<xmp></xmp>--></xmp>","<noembed><!--<noembed></noembed>--></noembed>","<!doctype html><table>\n","<!doctype html><table><td><span><font></span><span>","<!doctype html><form><table></form><form></table></form>"],"tests17.dat":["<!doctype html><table><tbody><select><tr>","<!doctype html><table><tr><select><td>","<!doctype html><table><tr><td><select><td>","<!doctype html><table><tr><th><select><td>","<!doctype html><table><caption><select><tr>","<!doctype html><select><tr>","<!doctype html><select><td>","<!doctype html><select><th>","<!doctype html><select><tbody>","<!doctype html><select><thead>","<!doctype html><select><tfoot>","<!doctype html><select><caption>","<!doctype html><table><tr></table>a"],"tests18.dat":["<plaintext></plaintext>","<!doctype html><plaintext></plaintext>","<!doctype html><html><plaintext></plaintext>","<!doctype html><head><plaintext></plaintext>","<!doctype html><html><noscript><plaintext></plaintext>","<!doctype html></head><plaintext></plaintext>","<!doctype html><body><plaintext></plaintext>","<!doctype html><table><plaintext></plaintext>","<!doctype html><table><tbody><plaintext></plaintext>","<!doctype html><table><tbody><tr><plaintext></plaintext>","<!doctype html><table><td><plaintext></plaintext>","<!doctype html><table><caption><plaintext></plaintext>","<!doctype html><table><colgroup><plaintext></plaintext>","<!doctype html><select><plaintext></plaintext>X","<!doctype html><table><select><plaintext>a<caption>b","<!doctype html><template><plaintext>a</template>b","<!doctype html><body></body><plaintext></plaintext>","<!doctype html><frameset><plaintext></plaintext>","<!doctype html><frameset></frameset><plaintext></plaintext>","<!doctype html><body></body></html><plaintext></plaintext>","<!doctype html><frameset></frameset></html><plaintext></plaintext>","<!doctype html><svg><plaintext>a</plaintext>b","<!doctype html><svg><title><plaintext>a</plaintext>b","<!doctype html><table><tr><style></script></style>abc","<!doctype html><table><tr><script></style></script>abc","<!doctype html><table><caption><style></script></style>abc","<!doctype html><table><td><style></script></style>abc","<!doctype html><select><script></style></script>abc","<!doctype html><table><select><script></style></script>abc","<!doctype html><table><tr><select><script></style></script>abc","<!doctype html><frameset></frameset><noframes>abc","<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc-->","<!doctype html><frameset></frameset></html><noframes>abc","<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc-->","<!doctype html><table><tr></tbody><tfoot>","<!doctype html><table><td><svg></svg>abc<td>"],"tests19.dat":["<!doctype html><math><mn DefinitionUrl=\"foo\">","<!doctype html><html></p><!--foo-->","<!doctype html><head></head></p><!--foo-->","<!doctype html><body><p><pre>","<!doctype html><body><p><listing>","<!doctype html><p><plaintext>","<!doctype html><p><h1>","<!doctype html><isindex type=\"hidden\">","<!doctype html><ruby><p><rp>","<!doctype html><ruby><div><span><rp>","<!doctype html><ruby><div><p><rp>","<!doctype html><ruby><p><rt>","<!doctype html><ruby><div><span><rt>","<!doctype html><ruby><div><p><rt>","<html><ruby>a<rb>b<rt></ruby></html>","<html><ruby>a<rp>b<rt></ruby></html>","<html><ruby>a<rt>b<rt></ruby></html>","<html><ruby>a<rtc>b<rt>c<rb>d</ruby></html>","<!doctype html><math/><foo>","<!doctype html><svg/><foo>","<!doctype html><div></body><!--foo-->","<!doctype html><h1><div><h3><span></h1>foo","<!doctype html><p></h3>foo","<!doctype html><h3><li>abc</h2>foo","<!doctype html><table>abc<!--foo-->","<!doctype html><table> <!--foo-->","<!doctype html><table> b <!--foo-->","<!doctype html><select><option><option>","<!doctype html><select><option></optgroup>","<!doctype html><dd><optgroup><dd>","<!doctype html><p><math><mi><p><h1>","<!doctype html><p><math><mo><p><h1>","<!doctype html><p><math><mn><p><h1>","<!doctype html><p><math><ms><p><h1>","<!doctype html><p><math><mtext><p><h1>","<!doctype html><frameset></noframes>","<!doctype html><html c=d><body></html><html a=b>","<!doctype html><html c=d><frameset></frameset></html><html a=b>","<!doctype html><html><frameset></frameset></html><!--foo-->","<!doctype html><html><frameset></frameset></html> ","<!doctype html><html><frameset></frameset></html>abc","<!doctype html><html><frameset></frameset></html><p>","<!doctype html><html><frameset></frameset></html></p>","<html><frameset></frameset></html><!doctype html>","<!doctype html><body><frameset>","<!doctype html><p><frameset><frame>","<!doctype html><p>a<frameset>","<!doctype html><p> <frameset><frame>","<!doctype html><pre><frameset>","<!doctype html><listing><frameset>","<!doctype html><li><frameset>","<!doctype html><dd><frameset>","<!doctype html><dt><frameset>","<!doctype html><button><frameset>","<!doctype html><applet><frameset>","<!doctype html><marquee><frameset>","<!doctype html><object><frameset>","<!doctype html><table><frameset>","<!doctype html><area><frameset>","<!doctype html><basefont><frameset>","<!doctype html><bgsound><frameset>","<!doctype html><br><frameset>","<!doctype html><embed><frameset>","<!doctype html><img><frameset>","<!doctype html><input><frameset>","<!doctype html><keygen><frameset>","<!doctype html><wbr><frameset>","<!doctype html><hr><frameset>","<!doctype html><textarea></textarea><frameset>","<!doctype html><xmp></xmp><frameset>","<!doctype html><iframe></iframe><frameset>","<!doctype html><select></select><frameset>","<!doctype html><svg></svg><frameset><frame>","<!doctype html><math></math><frameset><frame>","<!doctype html><svg><foreignObject><div> <frameset><frame>","<!doctype html><svg>a</svg><frameset><frame>","<!doctype html><svg> </svg><frameset><frame>","<html>aaa<frameset></frameset>","<html> a <frameset></frameset>","<!doctype html><div><frameset>","<!doctype html><div><body><frameset>","<!doctype html><p><math></p>a","<!doctype html><p><math><mn><span></p>a","<!doctype html><math></html>","<!doctype html><meta charset=\"ascii\">","<!doctype html><meta http-equiv=\"content-type\" content=\"text/html;charset=ascii\">","<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset=\"utf8\">","<!doctype html><html a=b><head></head><html c=d>","<!doctype html><image/>","<!doctype html>a<i>b<table>c<b>d</i>e</b>f","<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f","<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f","<!doctype html><table><i>a<b>b<div>c</i>","<!doctype html><table><i>a<div>b<tr>c<b>d</i>e","<!doctype html><table><td><table><i>a<div>b<b>c</i>d","<!doctype html><body><bgsound>","<!doctype html><body><basefont>","<!doctype html><a><b></a><basefont>","<!doctype html><a><b></a><bgsound>","<!doctype html><figcaption><article></figcaption>a","<!doctype html><summary><article></summary>a","<!doctype html><p><a><plaintext>b","<!DOCTYPE html><div>a<a></div>b<p>c</p>d"],"tests2.dat":["<!DOCTYPE html>Test","<textarea>test</div>test","<table><td>","<table><td>test</tbody></table>","<frame>test","<!DOCTYPE html><frameset>test","<!DOCTYPE html><frameset> te st","<!DOCTYPE html><frameset></frameset> te st","<!DOCTYPE html><frameset><!DOCTYPE html>","<!DOCTYPE html><font><p><b>test</font>","<!DOCTYPE html><dt><div><dd>","<script></x","<table><plaintext><td>","<plaintext></plaintext>","<!DOCTYPE html><table><tr>TEST","<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>","</b test","<!DOCTYPE html></b test<b &=&amp>X","<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt","&","&#","&#X","&#x","&#45","&x-test","<!doctypehtml><p><li>","<!doctypehtml><p><dt>","<!doctypehtml><p><dd>","<!doctypehtml><p><form>","<!DOCTYPE html><p></P>X","&AMP","&AMp;","<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>","<!DOCTYPE html>X</body>X","<!DOCTYPE html><!-- X","<!DOCTYPE html><table><caption>test TEST</caption><td>test","<!DOCTYPE html><select><option><optgroup>","<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>","<!DOCTYPE html><select><optgroup><option><optgroup>","<!DOCTYPE html><datalist><option>foo</datalist>bar","<!DOCTYPE html><font><input><input></font>","<!DOCTYPE html><!-- XXX - XXX -->","<!DOCTYPE html><!-- XXX - XXX","<!DOCTYPE html><!-- XXX - XXX - XXX -->","<!DOCTYPE html> <!DOCTYPE html>","test\ntest","<!DOCTYPE html><body><title>test</body></title>","<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>\nx { content:\"</style\" } </style>","<!DOCTYPE html><select><optgroup></optgroup></select>"," \n ","<!DOCTYPE html> <html>","<!DOCTYPE html><script>\n</script> <title>x</title> </head>","<!DOCTYPE html><html><body><html id=x>","<!DOCTYPE html>X</body><html id=\"x\">","<!DOCTYPE html><head><html id=x>","<!DOCTYPE html>X</html>X","<!DOCTYPE html>X</html> ","<!DOCTYPE html>X</html><p>X","<!DOCTYPE html>X<p/x/y/z>","<!DOCTYPE html><!--x--","<!DOCTYPE html><table><tr><td></p></table>","<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->","<!doctype html><div><form></form><div></div></div>"],"tests20.dat":["<!doctype html><p><button><button>","<!doctype html><p><button><address>","<!doctype html><p><button><article>","<!doctype html><p><button><aside>","<!doctype html><p><button><blockquote>","<!doctype html><p><button><center>","<!doctype html><p><button><details>","<!doctype html><p><button><dialog>","<!doctype html><p><button><dir>","<!doctype html><p><button><div>","<!doctype html><p><button><dl>","<!doctype html><p><button><fieldset>","<!doctype html><p><button><figcaption>","<!doctype html><p><button><figure>","<!doctype html><p><button><footer>","<!doctype html><p><button><header>","<!doctype html><p><button><hgroup>","<!doctype html><p><button><main>","<!doctype html><p><button><menu>","<!doctype html><p><button><nav>","<!doctype html><p><button><ol>","<!doctype html><p><button><p>","<!doctype html><p><button><search>","<!doctype html><p><button><section>","<!doctype html><p><button><summary>","<!doctype html><p><button><ul>","<!doctype html><p><button><h1>","<!doctype html><p><button><h6>","<!doctype html><p><button><listing>","<!doctype html><p><button><pre>","<!doctype html><p><button><form>","<!doctype html><p><button><li>","<!doctype html><p><button><dd>","<!doctype html><p><button><dt>","<!doctype html><p><button><plaintext>","<!doctype html><p><button><table>","<!doctype html><p><button><hr>","<!doctype html><p><button><xmp>","<!doctype html><p><button></p>","<!doctype html><button><p></button>x","<!doctype html><address><button></address>a","<p><table></p>","<!doctype html><svg>","<!doctype html><p><figcaption>","<!doctype html><p><summary>","<!doctype html><form><table><form>","<!doctype html><table><form><form>","<!doctype html><table><form></table><form>","<!doctype html><svg><foreignObject><p>","<!doctype html><svg><title>abc","<option><span><option>","<option><option>","<math><annotation-xml><div>","<math><annotation-xml encoding=\"application/svg+xml\"><div>","<math><annotation-xml encoding=\"application/xhtml+xml\"><div>","<math><annotation-xml encoding=\"aPPlication/xhtmL+xMl\"><div>","<math><annotation-xml encoding=\"text/html\"><div>","<math><annotation-xml encoding=\"Text/htmL\"><div>","<math><annotation-xml encoding=\" text/html \"><div>","<math><annotation-xml> </annotation-xml>","<math><annotation-xml>c</annotation-xml>","<math><annotation-xml><!--foo-->","<math><annotation-xml></svg>x","<math><annotation-xml><svg>x"],"tests21.dat":["<svg><![CDATA[foo]]>","<math><![CDATA[foo]]>","<div><![CDATA[foo]]>","<svg><![CDATA[foo","<svg><![CDATA[","<svg><![CDATA[]]>","<svg><![CDATA[]] >]]>","<svg><![CDATA[]]","<svg><![CDATA[]","<svg><![CDATA[]>a","<!DOCTYPE html><svg><![CDATA[foo]]]>","<!DOCTYPE html><svg><![CDATA[foo]]]]>","<!DOCTYPE html><svg><![CDATA[foo]]]]]>","<svg><foreignObject><div><![CDATA[foo]]>","<svg><![CDATA[<svg>]]>","<svg><![CDATA[</svg>a]]>","<svg><![CDATA[<svg>a","<svg><![CDATA[</svg>a","<svg><![CDATA[<svg>]]><path>","<svg><![CDATA[<svg>]]></path>","<svg><![CDATA[<svg>]]><!--path-->","<svg><![CDATA[<svg>]]>path","<svg><![CDATA[<!--svg-->]]>"],"tests22.dat":["<a><b><big><em><strong><div>X</a>","<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8>A</a>","<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9>A</a>","<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9><div id=10>A</a>","<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST"],"tests23.dat":["<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X","<p><font size=4><font size=4><font size=4><font size=4><p>X","<p><font size=4><font size=4><font size=4><font size=\"5\"><font size=4><p>X","<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X","<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y"],"tests24.dat":["<!DOCTYPE html>&NotEqualTilde;","<!DOCTYPE html>&NotEqualTilde;A","<!DOCTYPE html>&ThickSpace;","<!DOCTYPE html>&ThickSpace;A","<!DOCTYPE html>&NotSubset;","<!DOCTYPE html>&NotSubset;A","<!DOCTYPE html>&Gopf;","<!DOCTYPE html>&Gopf;A"],"tests25.dat":["<!DOCTYPE html><body><foo>A","<!DOCTYPE html><body><area>A","<!DOCTYPE html><body><base>A","<!DOCTYPE html><body><basefont>A","<!DOCTYPE html><body><bgsound>A","<!DOCTYPE html><body><br>A","<!DOCTYPE html><body><col>A","<!DOCTYPE html><body><command>A","<!DOCTYPE html><body><embed>A","<!DOCTYPE html><body><frame>A","<!DOCTYPE html><body><hr>A","<!DOCTYPE html><body><img>A","<!DOCTYPE html><body><input>A","<!DOCTYPE html><body><keygen>A","<!DOCTYPE html><keygen>A</keygen>B","</keygen>A","<!DOCTYPE html></keygen>A","<!DOCTYPE html><head></keygen>A","<!DOCTYPE html><head></head></keygen>A","<!DOCTYPE html><body></keygen>A","<!DOCTYPE html><body><link>A","<!DOCTYPE html><body><meta>A","<!DOCTYPE html><body><param>A","<!DOCTYPE html><body><source>A","<!DOCTYPE html><body><track>A","<!DOCTYPE html><body><wbr>A"],"tests26.dat":["<!DOCTYPE html><body><a href='#1'><nobr>1<nobr></a><br><a href='#2'><nobr>2<nobr></a><br><a href='#3'><nobr>3<nobr></a>","<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3","<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3","<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3","<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3","<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3","<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr>","<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2","<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i>","<p><code x</code></p>\n","<!DOCTYPE html><svg><foreignObject><p><i></p>a","<!DOCTYPE html><table><tr><td><svg><foreignObject><p><i></p>a","<!DOCTYPE html><math><mtext><p><i></p>a","<!DOCTYPE html><table><tr><td><math><mtext><p><i></p>a","<!DOCTYPE html><body><div><!/div>a","<button><p><button>","<svg></p><foo>","<svg></br><foo>","<math></p><foo>","<math></br><foo>"],"tests3.dat":["<head></head><style></style>","<head></head><script></script>","<head></head><!-- --><style></style><!-- --><script></script>","<head></head><!-- -->x<style></style><!-- --><script></script>","<!DOCTYPE html><html><head></head><body><pre>\n</pre></body></html>","<!DOCTYPE html><html><head></head><body><pre>\nfoo</pre></body></html>","<!DOCTYPE html><html><head></head><body><pre>\n\nfoo</pre></body></html>","<!DOCTYPE html><html><head></head><body><pre>\nfoo\n</pre></body></html>","<!DOCTYPE html><html><head></head><body><pre>x</pre><span>\n</span></body></html>","<!DOCTYPE html><html><head></head><body><pre>x\ny</pre></body></html>","<!DOCTYPE html><html><head></head><body><pre>x<div>\ny</pre></body></html>","<!DOCTYPE html><pre>&#x0a;&#x0a;A</pre>","<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>","<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>","<textarea>foo<span>bar</span><i>baz","<title>foo<span>bar</em><i>baz","<!DOCTYPE html><textarea>\n</textarea>","<!DOCTYPE html><textarea>\nfoo</textarea>","<!DOCTYPE html><textarea>\n\nfoo</textarea>","<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>","<!doctype html><nobr><nobr><nobr>","<!doctype html><nobr><nobr></nobr><nobr>","<!doctype html><html><body><p><table></table></body></html>","<p><table></table>"],"tests4.dat":["direct div content","direct textarea content","textarea content with <em>pseudo</em> <foo>markup","this is &#x0043;DATA inside a <style> element","</plaintext>","setting html's innerHTML","<title>setting head's innerHTML</title>","direct <title> content","<!-- inside </script> -->"],"tests5.dat":["<style> <!-- </style>x","<style> <!-- </style> --> </style>x","<style> <!--> </style>x","<style> <!---> </style>x","<iframe> <!---> </iframe>x","<iframe> <!--- </iframe>->x</iframe> --> </iframe>x","<script> <!-- </script> --> </script>x","<title> <!-- </title> --> </title>x","<textarea> <!--- </textarea>->x</textarea> --> </textarea>x","<style> <!</-- </style>x","<p><xmp></xmp>","<xmp> <!-- > --> </xmp>","<title>&amp;</title>","<title><!--&amp;--></title>","<title><!--</title>","<noscript><!--</noscript>--></noscript>","<noscript><!--</noscript>--></noscript>"],"tests6.dat":["<!doctype html></head> <head>","<!doctype html><form><div></form><div>","<!doctype html><title>&amp;</title>","<!doctype html><title><!--&amp;--></title>","<!doctype>","<!---x","<body>\n<div>","<frameset></frameset>\nfoo","<frameset></frameset>\n<noframes>","<frameset></frameset>\n<div>","<frameset></frameset>\n</html>","<frameset></frameset>\n</div>","<form><form>","<button><button>","<table><tr><td></th>","<table><caption><td>","<table><caption><div>","</caption><div>","<table><caption><div></caption>","<table><caption></table>","</table><div>","<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>","<table><caption><div></div>","<table><tr><td></body></caption></col></colgroup></html>","</table></tbody></tfoot></thead></tr><div>","<table><colgroup>foo","foo<col>","<table><colgroup></col>","<frameset><div>","</frameset><frame>","<frameset></div>","</body><div>","<table><tr><div>","</tr><td>","</tbody></tfoot></thead><td>","<table><tr><div><td>","<caption><col><colgroup><tbody><tfoot><thead><tr>","<table><tbody></thead>","</table><tr>","<table><tbody></body></caption></col></colgroup></html></td></th></tr>","<table><tbody></div>","<table><table>","<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>","</table><tr>","<body></body></html>","<html><frameset></frameset></html> ","<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"><html></html>","<param><frameset></frameset>","<source><frameset></frameset>","<track><frameset></frameset>","</html><frameset></frameset>","</body><frameset></frameset>"],"tests7.dat":["<!doctype html><body><title>X</title>","<!doctype html><table><title>X</title></table>","<!doctype html><head></head><title>X</title>","<!doctype html></head><title>X</title>","<!doctype html></head><base>X","<!doctype html></head><basefont>X","<!doctype html></head><bgsound>X","<!doctype html><table><meta></table>","<!doctype html><table>X<tr><td><table> <meta></table></table>","<!doctype html><html> <head>","<!doctype html> <head>","<!doctype html><table><style> <tr>x </style> </table>","<!doctype html><table><TBODY><script> <tr>x </script> </table>","<!doctype html><p><applet><p>X</p></applet>","<!doctype html><p><object type=\"application/x-non-existant-plugin\"><p>X</p></object>","<!doctype html><listing>\nX</listing>","<!doctype html><select><input>X","<!doctype html><select><select>X","<!doctype html><table><input type=hidDEN></table>","<!doctype html><table>X<input type=hidDEN></table>","<!doctype html><table> <input type=hidDEN></table>","<!doctype html><table> <input type='hidDEN'></table>","<!doctype html><table><input type=\" hidden\"><input type=hidDEN></table>","<!doctype html><table><select>X<tr>","<!doctype html><select>X</select>","<!DOCTYPE hTmL><html></html>","<!DOCTYPE HTML><html></html>","<body>X</body></body>","<div><p>a</x> b","<table><tr><td><code></code> </table>","<table><b><tr><td>aaa</td></tr>bbb</table>ccc","A<table><tr> B</tr> B</table>","A<table><tr> B</tr> </em>C</table>","<select><keygen>"],"tests8.dat":["<div>\n<div></div>\n</span>x","<div>x<div></div>\n</span>x","<div>x<div></div>x</span>x","<div>x<div></div>y</span>z","<table><div>x<div></div>x</span>x","<table><li><li></table>","x<table>x","x<table><table>x","<b>a<div></div><div></b>y","<a><div><p></a>"],"tests9.dat":["<!DOCTYPE html><math></math>","<!DOCTYPE html><body><math></math>","<!DOCTYPE html><math><mi>","<!DOCTYPE html><math><annotation-xml><svg><u>","<!DOCTYPE html><body><select><math></math></select>","<!DOCTYPE html><body><select><option><math></math></option></select>","<!DOCTYPE html><body><table><math></math></table>","<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>","<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>","<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>","<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>","<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>","<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>","<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>","<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux","<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux","<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux","<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux","<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux","<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz","<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz","<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>","<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>","<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>","<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>","<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>","<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>"],"tests_innerHTML_1.dat":["<body><span>","<span><body>","<span><body>","<body><span>","<frameset><span>","<span><frameset>","<span><frameset>","<frameset><span>","<table><tr>","</table><tr>","<a>","<a><caption>a","<a><colgroup><col>","<a><tbody><tr>","<a><tfoot><tr>","<a><thead><tr>","<a><tr>","<a><th>","<a><td>","<table></table><tbody>","</table><span>","<span></table>","</caption><span>","<span></caption><span>","<span><caption><span>","<span><col><span>","<span><colgroup><span>","<span><html><span>","<span><tbody><span>","<span><td><span>","<span><tfoot><span>","<span><thead><span>","<span><th><span>","<span><tr><span>","<span></table><span>","</colgroup><col>","<a><col>","<caption><a>","<col><a>","<colgroup><a>","<tbody><a>","<tfoot><a>","<thead><a>","</table><a>","<a><tr>","<a><td>","<td><table><tbody><a><tr>","</tr><td>","<td><table><a><tr></tr><tr>","<caption><td>","<col><td>","<colgroup><td>","<tbody><td>","<tfoot><td>","<thead><td>","<tr><td>","</table><td>","<td><table></table><td>","<caption><a>","<col><a>","<colgroup><a>","<tbody><a>","<tfoot><a>","<th><a>","<thead><a>","<tr><a>","</table><a>","</tbody><a>","</td><a>","</tfoot><a>","</thead><a>","</th><a>","</tr><a>","<table><td><td>","</select><option>","<input><option>","<keygen><option>","<textarea><option>","</html><!--abc-->","</frameset><frame>",""],"tricky01.dat":["<b><p>Bold </b> Not bold</p>\nAlso not bold.","<html>\n<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain\n<p>I should not be red. <font color=red>Red. <i>Italic and red.</p>\n<p>Italic and red. </i> Red.</font> I should not be red.</p>\n<b>Bold <i>Bold and italic</b> Only Italic </i> Plain","<html><body>\n<p><font size=\"7\">First paragraph.</p>\n<p>Second paragraph.</p></font>\n<b><p><i>Bold and Italic</b> Italic</p>","<html>\n<dl>\n<dt><b>Boo\n<dd>Goo?\n</dl>\n</html>","<html><body>\n<label><a><div>Hello<div>World</div></a></label> \n</body></html>","<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table>","<table><tr><p><a><p>You should see this text.","<TABLE>\n<TR>\n<CENTER><CENTER><TD></TD></TR><TR>\n<FONT>\n<TABLE><tr></tr></TABLE>\n</P>\n<a></font><font></a>\nThis page contains an insanely badly-nested tag sequence.","<html>\n<body>\n<b><nobr><div>This text is in a div inside a nobr</nobr>More text that should not be in the nobr, i.e., the\nnobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre>\n</body>\n</html>"],"void-in-phrasing.dat":["<!DOCTYPE html><body><p><br></p>","<!DOCTYPE html><body><p><br>text</p>","<!DOCTYPE html><body><p>before<br>after</p>","<!DOCTYPE html><body><p><br><br></p>","<!DOCTYPE html><body><p>a<br>b<br>c</p>","<!DOCTYPE html><body><h1><br></h1>","<!DOCTYPE html><body><p><input></p>","<!DOCTYPE html><body><p><img></p>","<!DOCTYPE html><body><p><wbr></p>","<!DOCTYPE html><body><p><embed></p>","<!DOCTYPE html><body><h2><input></h2>","<!DOCTYPE html><body><em><br></em>","<!DOCTYPE html><body><strong><br>text</strong>"],"webkit01.dat":["Test","<div></div>","<div>Test</div>","<di","<div>Hello</div>\n<script>\nconsole.log(\"PASS\");\n</script>\n<div>Bye</div>","<div foo=\"bar\">Hello</div>","<div>Hello</div>\n<script>\nconsole.log(\"FOO<span>BAR</span>BAZ\");\n</script>\n<div>Bye</div>","<foo bar=\"baz\"></foo><potato quack=\"duck\"></potato>","<foo bar=\"baz\"><potato quack=\"duck\"></potato></foo>","<foo></foo bar=\"baz\"><potato></potato quack=\"duck\">","</ tttt>","<div FOO ><img><img></div>","<p>Test</p<p>Test2</p>","<rdar://problem/6869687>","<A>test< /A>","&lt;","<body foo='bar'><body foo='baz' yo='mama'>","<body></br foo=\"bar\"></body>","<bdy><br foo=\"bar\"></body>","<body></body></br foo=\"bar\">","<bdy></body><br foo=\"bar\">","<html><body></body></html><!-- Hi there -->","<html><body></body></html><!-- Comment A --><!-- Comment B --><!-- Comment C --><!-- Comment D --><!-- Comment E -->","<html><body></body></html>x<!-- Hi there -->","<html><body></body></html>x<!-- Hi there --></html><!-- Again -->","<html><body></body></html>x<!-- Hi there --></body></html><!-- Again -->","<html><body></body>\n <!-- Hi there --></html>","<html><body></body></html>\n <!-- Hi there -->","<html><body><ruby><div><rp>xx</rp></div></ruby></body></html>","<html><body><ruby><div><rt>xx</rt></div></ruby></body></html>","<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6-->","<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>","<dd><dd><dt><dt><dd><li><li>","<div><b></div><div><nobr>a<nobr>","<head></head>\n<body></body>","<head></head> <style></style>ddd","<kbd><table></kbd><col><select><tr>","<kbd><table></kbd><col><select><tr></table><div>","<a><li><style></style><title></title></a>","<font></p><p><meta><title></title></font>","<a><center><title></title><a>","<svg><title><div>","<svg><title><rect><div>","<svg><title><svg><div>","<img <=\"\" FAIL>","<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul>","<svg><em><desc></em>","<table><tr><td><svg><desc><td></desc><circle>","<svg><tfoot></mi><td>","<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math>","<!doctype html><input type=\"hidden\"><frameset>","<!doctype html><input type=\"button\"><frameset>"],"webkit02.dat":["<foo bar=qux/>","<p id=\"status\"><noscript><strong>A</strong></noscript><span>B</span></p>","<p id=\"status\"><noscript><strong>A</strong></noscript><span>B</span></p>","<div><sarcasm><div></div></sarcasm></div>","<html><body><img src=\"\" border=\"0\" alt=\"><div>A</div></body></html>","<table><td></tbody>A","<table><td></thead>A","<table><td></tfoot>A","<table><thead><td></tbody>A","<legend>test</legend>","<table><input>","<b><em><dcell><postfield><postfield><postfield><postfield><missing_glyph><missing_glyph><missing_glyph><missing_glyph><hkern><aside></b></em>","<b><em><foo><foo><aside></b>","<b><em><foo><foo><aside></b></em>","<b><em><foo><foo><foo><aside></b>","<b><em><foo><foo><foo><aside></b></em>","<b><em><foo><foo><foo><foo><foo><foo><foo><foo><foo><foo><aside></b></em>","<b><em><foo><foob><foob><foob><foob><fooc><fooc><fooc><fooc><food><aside></b></em>","<option><XH<optgroup></optgroup>","<svg><foreignObject><div>foo</div><plaintext></foreignObject></svg><div>bar</div>","<svg><foreignObject></foreignObject><title></svg>foo","</foreignObject><plaintext><div>foo</div>","<svg xml:base xml:lang xml:space xml:baaah definitionurl>","<math definitionurl xlink:title xlink:show>","<math DEFINITIONURL>","<select><hr>","<select><option><hr>","<select><optgroup><option><hr>","<select><optgroup><hr>","<select><option><optgroup><hr>","<table><tr><td><select><hr>","<table><tr><td><select><option><hr>","<table><tr><td><select><optgroup><option><hr>","<table><tr><td><select><optgroup><hr>","<table><tr><td><select><option><optgroup><hr>","<select><div><i></div><option>option","<div><i></div><option>option","<select><div>div 1</div><button>button</button><div>div 2</div><datalist><option>option</option></datalist><div>div 3</div></select>","<select><button>button</select>","<select><datalist>datalist</select>","<select><button><select></select></button></select>","<select><button><div><select></select>","<select><div><option><img>option</option></div></select>","<select><input>","<select><button><selectedcontent></button><option>X","<select><button><selectedcontent></button><option>x<i>i<b>ib</i>b","<select><button><selectedcontent></button><option>X<option>Y","<select><button><selectedcontent></button><option>X<option selected>Y","<font><select><option>a</option></font></select>"]}
@@ -95,6 +95,41 @@ test('tokenizes a twig print in an attribute value', () => {
95
95
  assert.equal(/** @type {any} */ (attr.valueChunks[0]).atom.raw, '{{ url }}');
96
96
  });
97
97
 
98
+ test('tokenizes unquoted attribute values', () => {
99
+ const source = '<div id=target class=row data-note=1></div>';
100
+ const tokens = html(source);
101
+ assert.deepEqual(types(tokens), ['startTag', 'endTag']);
102
+ const tag = /** @type {any} */ (tokens[0]);
103
+ assert.equal(tag.raw, '<div id=target class=row data-note=1>');
104
+ assert.deepEqual(
105
+ tag.attrs.map((/** @type {any} */ a) => a.nameRaw),
106
+ ['id', 'class', 'data-note'],
107
+ );
108
+ assert.deepEqual(
109
+ tag.attrs.map((/** @type {any} */ a) => a.quote),
110
+ [null, null, null],
111
+ );
112
+ assert.deepEqual(
113
+ tag.attrs.map((/** @type {any} */ a) => a.valueChunks[0].text),
114
+ ['target', 'row', '1'],
115
+ );
116
+ });
117
+
118
+ test('keeps a slash inside an unquoted attribute value', () => {
119
+ const tokens = html('<div id=target/>');
120
+ const tag = /** @type {any} */ (tokens[0]);
121
+ assert.equal(tag.attrs[0].valueChunks[0].text, 'target/');
122
+ assert.equal(tag.selfClosing, false);
123
+ });
124
+
125
+ test('tokenizes twig inside an unquoted attribute value', () => {
126
+ const tokens = html('<div class={{ foo }}></div>');
127
+ const tag = /** @type {any} */ (tokens[0]);
128
+ const chunk = tag.attrs[0].valueChunks[0];
129
+ assert.equal(chunk.type, 'twig');
130
+ assert.equal(chunk.atom.raw, '{{ foo }}');
131
+ });
132
+
98
133
  test('tokenizes conditional attributes via twig between attributes', () => {
99
134
  const source = '<div class="row" {% if x %} id="y" {% endif %} data-x>';
100
135
  const tokens = html(source);
@@ -145,6 +180,81 @@ test('preserves self-closing tags', () => {
145
180
  assert.equal(tokens[0].raw, '<link rel="x" />');
146
181
  });
147
182
 
183
+ test('does not hang on an end tag with an equals sign in its tail', () => {
184
+ const source = '</div class=x>tail';
185
+ const tokens = html(source);
186
+ assert.deepEqual(types(tokens), ['endTag', 'text']);
187
+ assert.equal(tokens[0].raw, '</div class=x>');
188
+ assert.equal(tokens[1].raw, 'tail');
189
+ assertContiguous(source, tokens);
190
+ });
191
+
192
+ test('keeps the written tag name on an end tag with attributes', () => {
193
+ // the spec reuses the before-attribute-name states for end tags; the tag
194
+ // name is never overwritten by the attribute text
195
+ for (const source of ['</div a>', '</div class=x>', '</div =1>', '</div a=b c=d>']) {
196
+ const tokens = html(source);
197
+ assert.equal(tokens[0].type, 'endTag', source);
198
+ assert.equal(tokens[0].name, 'div', source);
199
+ assert.equal(tokens[0].raw, source);
200
+ assertContiguous(source, tokens);
201
+ }
202
+ });
203
+
204
+ test('an appropriate end tag closes raw text; a name prefix does not', () => {
205
+ const tokens = html('<script>var x = "</scripture>";</script>');
206
+ assert.deepEqual(types(tokens), ['startTag', 'text', 'endTag']);
207
+ assert.equal(tokens[1].raw, 'var x = "</scripture>";');
208
+ assert.equal(tokens[2].raw, '</script>');
209
+ });
210
+
211
+ test('closes raw text on a trimmed appropriate end tag', () => {
212
+ // whitespace and `/` after the name still make it an appropriate end tag
213
+ for (const source of ['<style>a</style >', '<script>x</script/>', '<script>x</script >']) {
214
+ const tokens = html(source);
215
+ assert.equal(tokens[0].type, 'startTag', source);
216
+ assert.equal(tokens[1].raw, source.startsWith('<style>') ? 'a' : 'x', source);
217
+ assert.equal(tokens[2].type, 'endTag', source);
218
+ assertContiguous(source, tokens);
219
+ }
220
+ });
221
+
222
+ test('treats every RAWTEXT element as opaque content', () => {
223
+ for (const name of ['script', 'style', 'xmp', 'iframe', 'noembed', 'noframes']) {
224
+ const source = `<${ name }><b x=y>{{ v }}</b></${ name }>`;
225
+ const tokens = html(source);
226
+ assert.deepEqual(types(tokens), ['startTag', 'text', 'twig', 'text', 'endTag'], name);
227
+ assert.equal(tokens[0].name, name);
228
+ }
229
+ });
230
+
231
+ test('keeps an unterminated raw-text end tag as text', () => {
232
+ // EOF before `>`: the `</name` run is raw text and the element stays open
233
+ for (const name of ['script', 'style', 'xmp', 'iframe']) {
234
+ const source = `<${ name }>x</${ name }`;
235
+ const tokens = html(source);
236
+ assert.deepEqual(types(tokens), ['startTag', 'text'], name);
237
+ assert.equal(tokens[1].raw, `x</${ name }`, name);
238
+ assertContiguous(source, tokens);
239
+ }
240
+ });
241
+
242
+ test('does not treat noscript as raw text', () => {
243
+ const tokens = html('<noscript><b>x</b></noscript>');
244
+ assert.deepEqual(types(tokens), ['startTag', 'startTag', 'text', 'endTag', 'endTag']);
245
+ });
246
+
247
+ test('does not emit overlapping tokens for a bogus comment', () => {
248
+ for (const source of ['<!- x>', '<!-a', '<?']) {
249
+ const tokens = html(source);
250
+ assertContiguous(source, tokens);
251
+ assert.ok(tokens.every((t) => t.type === 'comment' || t.type === 'text'), source);
252
+ }
253
+ assert.deepEqual(types(html('<!- x>')), ['comment']);
254
+ assert.deepEqual(types(html('<?')), ['text']);
255
+ assert.deepEqual(types(html('<?x>')), ['comment']);
256
+ });
257
+
148
258
  test('treats a stray < followed by twig as text', () => {
149
259
  const source = '< {{ x }}';
150
260
  const tokens = html(source);
@@ -0,0 +1,68 @@
1
+ // @ts-check
2
+ /**
3
+ * Resource-bound tests for the hybrid parser.
4
+ *
5
+ * Untrusted template source must never be able to exhaust the stack or build an
6
+ * unboundedly deep tree. These cases nest far past any realistic document and
7
+ * assert that parsing stays flat and does not throw.
8
+ *
9
+ * @module test
10
+ */
11
+ import { test } from 'node:test';
12
+ import assert from 'node:assert/strict';
13
+ import { parse } from '@mrhenry/twig-html-parser';
14
+
15
+ /**
16
+ * The deepest element nesting, measured iteratively so the assertion itself
17
+ * cannot overflow the stack.
18
+ *
19
+ * @param {ReturnType<typeof parse>} root
20
+ * @returns {number}
21
+ */
22
+ function maxDepth(root) {
23
+ let max = 0;
24
+ const stack = [{ node: root, depth: 0 }];
25
+
26
+ for (;;) {
27
+ const entry = stack.pop();
28
+ if (!entry) {
29
+ break;
30
+ }
31
+
32
+ const { node, depth } = entry;
33
+ if (depth > max) {
34
+ max = depth;
35
+ }
36
+ if (Array.isArray(node.children)) {
37
+ for (const child of node.children) {
38
+ stack.push({ node: child, depth: depth + 1 });
39
+ }
40
+ }
41
+ }
42
+
43
+ return max;
44
+ }
45
+
46
+ test('deeply nested elements are depth-capped instead of overflowing the stack', () => {
47
+ const depth = 20000;
48
+ const source = `${'<div>'.repeat(depth)}x${'</div>'.repeat(depth)}`;
49
+
50
+ const tree = parse(source);
51
+
52
+ assert.ok(maxDepth(tree) <= 257, 'element depth stays bounded');
53
+ });
54
+
55
+ test('deeply nested twig blocks do not overflow the stack', () => {
56
+ const depth = 20000;
57
+ const source = `${'{% if x %}'.repeat(depth)}x${'{% endif %}'.repeat(depth)}`;
58
+
59
+ const tree = parse(source);
60
+
61
+ assert.ok(maxDepth(tree) <= 257, 'block depth stays bounded');
62
+ });
63
+
64
+ test('a single element beyond the cap is still represented as text', () => {
65
+ const tree = parse('<div class="a">x</div>');
66
+
67
+ assert.ok(maxDepth(tree) >= 1);
68
+ });
@@ -171,6 +171,31 @@ test('twig block indentation spans are contiguous with source', () => {
171
171
  assertOffsetsInSource(root, source);
172
172
  });
173
173
 
174
+ test('an end tag with attributes still closes the element', () => {
175
+ // the tag name is `div` even though the end tag carries a tail
176
+ const source = '<div>a</div class=x>b';
177
+ const root = ast(source);
178
+ const div = root.children[0];
179
+ assert.equal(div.type, 'element');
180
+ assert.equal(div.name, 'div');
181
+ assert.equal(div.endTagRaw, '</div class=x>');
182
+ assert.equal(root.children[1].raw, 'b');
183
+ assertOffsetsInSource(root, source);
184
+ });
185
+
186
+ test('raw text with an inappropriate end tag stays a single element', () => {
187
+ const source = '<script>var x = "</scripture>";</script>';
188
+ const root = ast(source);
189
+ assert.equal(root.children.length, 1);
190
+ const script = root.children[0];
191
+ assert.equal(script.name, 'script');
192
+ assert.equal(script.children.length, 1);
193
+ assert.equal(script.children[0].type, 'text');
194
+ assert.equal(script.children[0].raw, 'var x = "</scripture>";');
195
+ assert.equal(script.endTagRaw, '</script>');
196
+ assertOffsetsInSource(root, source);
197
+ });
198
+
174
199
  test('parser summary', () => {
175
200
  assert.ok(true);
176
201
  });
@@ -0,0 +1,114 @@
1
+ // @ts-check
2
+ /**
3
+ * WPT html5lib tokenizer corpus tests.
4
+ *
5
+ * `fixtures/wpt-html5lib-inputs.json` holds the `#data` sections of the
6
+ * upstream html5lib suite (`wpt/html/syntax/parsing/resources/*.dat`). They are
7
+ * a broad corpus of real and malformed HTML inputs (script data, comments,
8
+ * doctypes, attributes, foreign content, …). Our tokenizer does not implement
9
+ * tree construction, so the expected DOM trees do not apply; instead every
10
+ * input must tokenize to a contiguous, source-ordered list with exact offsets,
11
+ * without hanging.
12
+ *
13
+ * A few cases also assert the tokenizer-level outcome the spec defines (an
14
+ * inappropriate end tag that stays raw text, an end tag carrying attributes).
15
+ *
16
+ * @module test
17
+ */
18
+ import { test } from 'node:test';
19
+ import assert from 'node:assert/strict';
20
+ import { readFileSync } from 'node:fs';
21
+ import { Lexer, Source } from '@mrhenry/twig-tokenizer';
22
+ import { extractAtoms, tokenizeHtml } from '@mrhenry/twig-html-parser';
23
+
24
+ /** @type {Record<string, string[]>} */
25
+ const corpus = JSON.parse(
26
+ readFileSync( new URL( './fixtures/wpt-html5lib-inputs.json', import.meta.url ), 'utf8' ),
27
+ );
28
+
29
+ /**
30
+ * @param {string} source
31
+ * @returns {ReturnType<typeof tokenizeHtml>}
32
+ */
33
+ function html( source ) {
34
+ const tokens = new Lexer().tokenize( new Source( source, 'index.twig' ) ).getTokens();
35
+ return tokenizeHtml( extractAtoms( source, tokens ), source );
36
+ }
37
+
38
+ /**
39
+ * Asserts the token list covers the source contiguously and in order.
40
+ *
41
+ * @param {string} source
42
+ * @param {ReturnType<typeof tokenizeHtml>} tokens
43
+ */
44
+ function assertContiguous( source, tokens ) {
45
+ let prev = 0;
46
+ for ( const token of tokens ) {
47
+ assert.ok( token.rawStart >= prev, `token out of order at ${ token.rawStart } (prev ${ prev })` );
48
+ assert.ok( token.rawStart === prev, `gap at ${ token.rawStart } (prev ${ prev })` );
49
+ assert.ok( token.rawEnd >= token.rawStart, `negative span at ${ token.rawStart }` );
50
+ prev = token.rawEnd;
51
+ }
52
+ assert.equal( prev, source.length, `trailing gap (covered ${ prev }/${ source.length })` );
53
+ }
54
+
55
+ for ( const [ file, inputs ] of Object.entries( corpus ) ) {
56
+ test( `WPT html5lib tokenizer corpus: ${ file } (${ inputs.length } inputs)`, () => {
57
+ for ( const source of inputs ) {
58
+ assertContiguous( source, html( source ) );
59
+ }
60
+ } );
61
+ }
62
+
63
+ test( 'WPT: an inappropriate end tag stays inside script data', () => {
64
+ const source = 'FOO<script type="text/plain"></scriptx>BAR';
65
+ const tokens = html( source );
66
+ assert.deepEqual( tokens.map( ( token ) => token.type ), [ 'text', 'startTag', 'text' ] );
67
+ assert.equal( tokens[ 2 ].raw, '</scriptx>BAR' );
68
+ } );
69
+
70
+ test( 'WPT: an end tag with attributes closes at the correct `>`', () => {
71
+ const source = 'FOO<script></script foo=">" dd>BAR';
72
+ const tokens = html( source );
73
+ assert.deepEqual( tokens.map( ( token ) => token.type ), [ 'text', 'startTag', 'endTag', 'text' ] );
74
+ assert.equal( tokens[ 2 ].name, 'script' );
75
+ assert.equal( tokens[ 2 ].raw, '</script foo=">" dd>' );
76
+ assert.equal( tokens[ 3 ].raw, 'BAR' );
77
+ } );
78
+
79
+ test( 'WPT: comment end bang and abrupt comment closings', () => {
80
+ for ( const [ source, types ] of /** @type {Array<[string, string[]]>} */ ( [
81
+ [ 'FOO<!-- BAR --!>BAZ', [ 'text', 'comment', 'text' ] ],
82
+ [ '<!---->BAZ', [ 'comment', 'text' ] ],
83
+ [ '<!-- BAR -- >BAZ', [ 'comment' ] ],
84
+ ] ) ) {
85
+ assert.deepEqual( html( source ).map( ( token ) => token.type ), types, source );
86
+ }
87
+ } );
88
+
89
+ test( 'WPT: unquoted attribute values', () => {
90
+ // tests22.dat: `<div id=1>` — the value runs to whitespace or `>`
91
+ const tokens = html( '<div id=1><div id=2>A' );
92
+ const first = /** @type {any} */ ( tokens[ 0 ] );
93
+ assert.equal( first.type, 'startTag' );
94
+ assert.equal( first.attrs[ 0 ].nameRaw, 'id' );
95
+ assert.equal( first.attrs[ 0 ].quote, null );
96
+ assert.deepEqual( first.attrs[ 0 ].valueChunks.map( ( /** @type {any} */ c ) => c.text ), [ '1' ] );
97
+
98
+ // `>` terminates an unquoted value, so the tag closes
99
+ assert.deepEqual( html( '<div id=foo>' ).map( ( token ) => token.type ), [ 'startTag' ] );
100
+
101
+ // a `/` is part of an unquoted value, not a self-closing marker
102
+ const trailing = /** @type {any} */ ( html( '<div id=foo/>' )[ 0 ] );
103
+ assert.equal( trailing.selfClosing, false );
104
+ assert.deepEqual( trailing.attrs[ 0 ].valueChunks.map( ( /** @type {any} */ c ) => c.text ), [ 'foo/' ] );
105
+ } );
106
+
107
+ test( 'WPT: an unterminated raw-text end tag stays text', () => {
108
+ // scriptdata01.dat covers eof-in-script; a `</script` without `>` is data
109
+ const tokens = html( '<script>x</script' );
110
+ assert.deepEqual( tokens.map( ( token ) => token.type ), [ 'startTag', 'text' ] );
111
+ assert.equal( tokens[ 1 ].raw, 'x</script' );
112
+
113
+ assert.deepEqual( html( '<style>x</style' ).map( ( token ) => token.type ), [ 'startTag', 'text' ] );
114
+ } );