Version 0.6.18.0 .

svn merge -r 25988:26167 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@26168 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analyzer_experimental/bin/formatter.dart b/pkg/analyzer_experimental/bin/formatter.dart
new file mode 100755
index 0000000..dd25180
--- /dev/null
+++ b/pkg/analyzer_experimental/bin/formatter.dart
@@ -0,0 +1,93 @@
+#!/usr/bin/env dart
+
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:args/args.dart';
+
+import 'package:analyzer_experimental/src/services/formatter_impl.dart';
+
+
+const BINARY_NAME = 'dartfmt';
+final argParser = _initArgParser();
+
+void main() {
+  var options = argParser.parse(new Options().arguments);
+  if (options['help']) {
+    _printUsage();
+    return;
+  }
+  if (options.rest.isEmpty) {
+    _formatStdin(options);
+  } else {
+    _formatFiles(options.rest);
+  }
+}
+
+_formatFiles(files) {
+  for (var file in files) {
+    _formatFile(file);
+  }
+}
+
+_formatFile(path) {
+  var buffer = new StringBuffer();
+  var file = new File(path);
+  file.openRead()
+      .transform(new StringDecoder())
+      .listen((data) =>  buffer.write(data),
+        onError: (error) => print('Error, could not open "$path"'),
+        onDone: () => print(_formatCU(buffer.toString())));
+}
+
+_formatStdin(options) {
+  _log('not supported yet!');
+//  stdin.transform(new StringDecoder())
+//      .listen((String data) => print(data),
+//        onError: (error) => print('Error reading from stdin'),
+//        onDone: () => print('Finished reading data'));
+}
+
+/// Initialize the arg parser instance.
+ArgParser _initArgParser() {
+  // NOTE: these flags are placeholders only!
+  var parser = new ArgParser();
+  parser.addFlag('write', abbr: 'w', negatable: false,
+      help: 'Write reformatted sources to files (overwriting contents).  '
+            'Do not print reformatted sources to standard output.');
+  parser.addFlag('help', abbr: 'h', negatable: false,
+      help: 'Print this usage information.');
+  return parser;
+}
+
+
+/// Displays usage information.
+_printUsage() {
+  var buffer = new StringBuffer();
+  buffer..write('$BINARY_NAME formats Dart programs.')
+        ..write('\n\n')
+        ..write('Without an explicit path, $BINARY_NAME processes the standard '
+                'input.  Given a file, it operates on that file; given a '
+                'directory, it operates on all .dart files in that directory, '
+                'recursively. (Files starting with a period are ignored.) By '
+                'default, $BINARY_NAME prints the reformatted sources to '
+                'standard output.')
+        ..write('\n\n')
+        ..write('Supported flags are:')
+        ..write('Usage: $BINARY_NAME [flags] [path...]\n\n')
+        ..write('${argParser.getUsage()}\n\n');
+  _log(buffer.toString());
+}
+
+/// Format the given [src] as a compilation unit.
+String _formatCU(src, {options: const FormatterOptions()}) =>
+    new CodeFormatter(options).format(CodeKind.COMPILATION_UNIT, src);
+
+/// Log the given [msg].
+_log(String msg) {
+  //TODO(pquitslund): add proper log support
+  print(msg);
+}
\ No newline at end of file
diff --git a/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart b/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
index cb2b7b9..22e0d2a 100644
--- a/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
@@ -161,63 +161,60 @@
   }
 
   visitAnnotation(Annotation node) {
-    writer.print('@');
+    emitToken(node.atSign);
     visit(node.name);
     visitPrefixed('.', node.constructorName);
     visit(node.arguments);
   }
 
   visitArgumentDefinitionTest(ArgumentDefinitionTest node) {
-    writer.print('?');
+    emitToken(node.question);
     visit(node.identifier);
   }
 
   visitArgumentList(ArgumentList node) {
-    writer.print('(');
+    emitToken(node.leftParenthesis);
     visitList(node.arguments, ', ');
-    writer.print(')');
+    emitToken(node.rightParenthesis);
   }
 
   visitAsExpression(AsExpression node) {
     visit(node.expression);
-    writer.print(' as ');
+    emitToken(node.asOperator, prefix: ' ', suffix: ' ');
     visit(node.type);
   }
 
   visitAssertStatement(AssertStatement node) {
-    writer.print('assert (');
+    emitToken(node.keyword, suffix: ' (');
     visit(node.condition);
-    writer.print(');');
+    emitToken(node.semicolon, prefix: ')');
   }
 
   visitAssignmentExpression(AssignmentExpression node) {
     visit(node.leftHandSide);
-    writer.print(' ');
-    writer.print(node.operator.lexeme);
-    writer.print(' ');
+    emitToken(node.operator, prefix: ' ', suffix: ' ');
     visit(node.rightHandSide);
   }
 
   visitBinaryExpression(BinaryExpression node) {
     visit(node.leftOperand);
-    writer.print(' ');
-    writer.print(node.operator.lexeme);
-    writer.print(' ');
+    emitToken(node.operator, prefix: ' ', suffix: ' ');
     visit(node.rightOperand);
   }
 
   visitBlock(Block node) {
-    writer.print('{');
-    writer.indent();
+    emitToken(node.leftBracket);
+    indent();
 
     for (var stmt in node.statements) {
-      writer.newline();
       visit(stmt);
     }
 
-    writer.unindent();
-    writer.newline();
-    writer.print('}');
+    unindent();
+    newline();
+    print('}');
+//TODO(pquitslund): make this work    
+//    emitToken(node.rightBracket);
     previousToken = node.rightBracket;
   }
 
@@ -226,13 +223,13 @@
   }
 
   visitBooleanLiteral(BooleanLiteral node) {
-    writer.print(node.literal.lexeme);
+    emitToken(node.literal);
   }
 
   visitBreakStatement(BreakStatement node) {
-    writer.print('break');
+    emitToken(node.keyword);
     visitPrefixed(' ', node.label);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitCascadeExpression(CascadeExpression node) {
@@ -244,53 +241,51 @@
     visitPrefixed('on ', node.exceptionType);
     if (node.catchKeyword != null) {
       if (node.exceptionType != null) {
-        writer.print(' ');
+        print(' ');
       }
-      writer.print('catch (');
+      print('catch (');
       visit(node.exceptionParameter);
       visitPrefixed(', ', node.stackTraceParameter);
-      writer.print(') ');
+      print(') ');
     } else {
-      writer.print(' ');
+      print(' ');
     }
     visit(node.body);
+    newline();
   }
 
   visitClassDeclaration(ClassDeclaration node) {
-    emitToken(node.abstractKeyword, ' ');
-    emitToken(node.classKeyword, ' ');
+    emitToken(node.abstractKeyword, suffix: ' ');
+    emitToken(node.classKeyword, suffix: ' ');
     visit(node.name);
     visit(node.typeParameters);
     visitPrefixed(' ', node.extendsClause);
     visitPrefixed(' ', node.withClause);
     visitPrefixed(' ', node.implementsClause);
-//    writer.print(' {');
-//    writer.print(' ');
-//    emit(node.leftBracket);
-    emitPrefixedToken(' ', node.leftBracket);
-    writer.indent();
+    emitToken(node.leftBracket, prefix: ' ');
+    indent();
 
     for (var i = 0; i < node.members.length; i++) {
       visit(node.members[i]);
     }
 
-    writer.unindent();
+    unindent();
 
-    emit(node.rightBracket, min: 1);
+    emitToken(node.rightBracket, minNewlines: 1);
   }
 
   visitClassTypeAlias(ClassTypeAlias node) {
-    writer.print('typedef ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.name);
     visit(node.typeParameters);
-    writer.print(' = ');
+    print(' = ');
     if (node.abstractKeyword != null) {
-      writer.print('abstract ');
+      print('abstract ');
     }
     visit(node.superclass);
     visitPrefixed(' ', node.withClause);
     visitPrefixed(' ', node.implementsClause);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitComment(Comment node) => null;
@@ -308,21 +303,21 @@
     visitPrefixedList(prefix, node.declarations);
 
     //TODO(pquitslund): move this?
-    writer.newline();
+    newline();
   }
 
   visitConditionalExpression(ConditionalExpression node) {
     visit(node.condition);
-    writer.print(' ? ');
+    print(' ? ');
     visit(node.thenExpression);
-    writer.print(' : ');
+    print(' : ');
     visit(node.elseExpression);
   }
 
   visitConstructorDeclaration(ConstructorDeclaration node) {
-    emitToken(node.externalKeyword, ' ');
-    emitToken(node.constKeyword, ' ');
-    emitToken(node.factoryKeyword, ' ');
+    emitToken(node.externalKeyword, suffix: ' ');
+    emitToken(node.constKeyword, suffix: ' ');
+    emitToken(node.factoryKeyword, suffix: ' ');
     visit(node.returnType);
     visitPrefixed('.', node.name);
     visit(node.parameters);
@@ -332,9 +327,9 @@
   }
 
   visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
-    emitToken(node.keyword, '.');
+    emitToken(node.keyword, suffix: '.');
     visit(node.fieldName);
-    writer.print(' = ');
+    print(' = ');
     visit(node.expression);
   }
 
@@ -344,13 +339,13 @@
   }
 
   visitContinueStatement(ContinueStatement node) {
-    writer.print('continue');
+    emitToken(node.keyword);
     visitPrefixed(' ', node.label);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitDeclaredIdentifier(DeclaredIdentifier node) {
-    emitToken(node.keyword, ' ');
+    emitToken(node.keyword, suffix: ' ');
     visitSuffixed(node.type, ' ');
     visit(node.identifier);
   }
@@ -358,138 +353,136 @@
   visitDefaultFormalParameter(DefaultFormalParameter node) {
     visit(node.parameter);
     if (node.separator != null) {
-      writer.print(' ');
-      writer.print(node.separator.lexeme);
+      print(' ');
+      print(node.separator.lexeme);
       visitPrefixed(' ', node.defaultValue);
     }
   }
 
   visitDoStatement(DoStatement node) {
-    writer.print('do ');
+    emitToken(node.doKeyword, suffix: ' ');
     visit(node.body);
-    writer.print(' while (');
+    emitToken(node.whileKeyword, prefix: ' ', suffix: ' (');
     visit(node.condition);
-    writer.print(');');
+    emitToken(node.semicolon, prefix: ')');
   }
 
   visitDoubleLiteral(DoubleLiteral node) {
-    writer.print(node.literal.lexeme);
+    print(node.literal.lexeme);
   }
 
   visitEmptyFunctionBody(EmptyFunctionBody node) {
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitEmptyStatement(EmptyStatement node) {
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitExportDirective(ExportDirective node) {
-    writer.print('export ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.uri);
     visitPrefixedList(' ', node.combinators, ' ');
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitExpressionFunctionBody(ExpressionFunctionBody node) {
-    writer.print('=> ');
+    emitToken(node.functionDefinition, suffix: ' ');
     visit(node.expression);
-    if (node.semicolon != null) {
-      writer.print(';');
-    }
+    emitToken(node.semicolon);
   }
 
   visitExpressionStatement(ExpressionStatement node) {
     visit(node.expression);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitExtendsClause(ExtendsClause node) {
-    writer.print('extends ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.superclass);
   }
 
   visitFieldDeclaration(FieldDeclaration node) {
-    emitToken(node.keyword, ' ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.fields);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitFieldFormalParameter(FieldFormalParameter node) {
-    emitToken(node.keyword, ' ');
+    emitToken(node.keyword, suffix: ' ');
     visitSuffixed(node.type, ' ');
-    writer.print('this.');
+    print('this.');
     visit(node.identifier);
     visit(node.parameters);
   }
 
   visitForEachStatement(ForEachStatement node) {
-    writer.print('for (');
+    print('for (');
     visit(node.loopVariable);
-    writer.print(' in ');
+    print(' in ');
     visit(node.iterator);
-    writer.print(') ');
+    print(') ');
     visit(node.body);
   }
 
   visitFormalParameterList(FormalParameterList node) {
     var groupEnd = null;
-    writer.print('(');
+    print('(');
     var parameters = node.parameters;
     var size = parameters.length;
     for (var i = 0; i < size; i++) {
       var parameter = parameters[i];
       if (i > 0) {
-        writer.print(', ');
+        print(', ');
       }
       if (groupEnd == null && parameter is DefaultFormalParameter) {
         if (identical(parameter.kind, ParameterKind.NAMED)) {
           groupEnd = '}';
-          writer.print('{');
+          print('{');
         } else {
           groupEnd = ']';
-          writer.print('[');
+          print('[');
         }
       }
       parameter.accept(this);
     }
     if (groupEnd != null) {
-      writer.print(groupEnd);
+      print(groupEnd);
     }
-    writer.print(')');
+    print(')');
   }
 
   visitForStatement(ForStatement node) {
     var initialization = node.initialization;
-    writer.print('for (');
+    print('for (');
     if (initialization != null) {
       visit(initialization);
     } else {
       visit(node.variables);
     }
-    writer.print(';');
+    print(';');
     visitPrefixed(' ', node.condition);
-    writer.print(';');
+    print(';');
     visitPrefixedList(' ', node.updaters, ', ');
-    writer.print(') ');
+    print(') ');
     visit(node.body);
   }
 
   visitFunctionDeclaration(FunctionDeclaration node) {
     visitSuffixed(node.returnType, ' ');
-    emitToken(node.propertyKeyword, ' ');
+    emitToken(node.propertyKeyword, suffix: ' ');
     visit(node.name);
     visit(node.functionExpression);
   }
 
   visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
     visit(node.functionDeclaration);
-    writer.print(';');
+    print(';');
   }
 
   visitFunctionExpression(FunctionExpression node) {
     visit(node.parameters);
-    writer.print(' ');
+    print(' ');
     visit(node.body);
   }
 
@@ -499,12 +492,12 @@
   }
 
   visitFunctionTypeAlias(FunctionTypeAlias node) {
-    writer.print('typedef ');
+    emitToken(node.keyword, suffix: ' ');
     visitSuffixed(node.returnType, ' ');
     visit(node.name);
     visit(node.typeParameters);
     visit(node.parameters);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
@@ -514,82 +507,81 @@
   }
 
   visitHideCombinator(HideCombinator node) {
-    writer.print('hide ');
+    emitToken(node.keyword, suffix: ' ');
     visitList(node.hiddenNames, ', ');
   }
 
   visitIfStatement(IfStatement node) {
-    writer.print('if (');
+    emitToken(node.ifKeyword);
+    print(' (');
     visit(node.condition);
-    writer.print(') ');
+    print(') ');
     visit(node.thenStatement);
     visitPrefixed(' else ', node.elseStatement);
   }
 
   visitImplementsClause(ImplementsClause node) {
-    writer.print('implements ');
+    emitToken(node.keyword, suffix: ' ');
     visitList(node.interfaces, ', ');
   }
 
   visitImportDirective(ImportDirective node) {
-    writer.print('import ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.uri);
     visitPrefixed(' as ', node.prefix);
     visitPrefixedList(' ', node.combinators, ' ');
-//    writer.print(';');
-    emit(node.semicolon);
-//    writer.newline();
+    emitToken(node.semicolon);
   }
 
   visitIndexExpression(IndexExpression node) {
     if (node.isCascaded) {
-      writer.print('..');
+      print('..');
     } else {
       visit(node.target);
     }
-    writer.print('[');
+    print('[');
     visit(node.index);
-    writer.print(']');
+    print(']');
   }
 
   visitInstanceCreationExpression(InstanceCreationExpression node) {
-    emitToken(node.keyword, ' ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.constructorName);
     visit(node.argumentList);
   }
 
   visitIntegerLiteral(IntegerLiteral node) {
-    writer.print(node.literal.lexeme);
+    print(node.literal.lexeme);
   }
 
   visitInterpolationExpression(InterpolationExpression node) {
     if (node.rightBracket != null) {
-      writer.print('\${');
+      print('\${');
       visit(node.expression);
-      writer.print('}');
+      print('}');
     } else {
-      writer.print('\$');
+      print('\$');
       visit(node.expression);
     }
   }
 
   visitInterpolationString(InterpolationString node) {
-    writer.print(node.contents.lexeme);
+    print(node.contents.lexeme);
   }
 
   visitIsExpression(IsExpression node) {
     visit(node.expression);
     if (node.notOperator == null) {
-      writer.print(' is ');
+      print(' is ');
     } else {
-      writer.print(' is! ');
+      print(' is! ');
     }
     visit(node.type);
   }
 
   visitLabel(Label node) {
     visit(node.label);
-    writer.print(':');
+    print(':');
   }
 
   visitLabeledStatement(LabeledStatement node) {
@@ -598,49 +590,49 @@
   }
 
   visitLibraryDirective(LibraryDirective node) {
-    writer.print('library ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.name);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitLibraryIdentifier(LibraryIdentifier node) {
-    writer.print(node.name);
+    print(node.name);
   }
 
   visitListLiteral(ListLiteral node) {
     if (node.modifier != null) {
-      writer.print(node.modifier.lexeme);
-      writer.print(' ');
+      print(node.modifier.lexeme);
+      print(' ');
     }
-    visitSuffixed(node.typeArguments, ' ');
-    writer.print('[');
+    visit(node.typeArguments);
+    print('[');
     visitList(node.elements, ', ');
-    writer.print(']');
+    print(']');
   }
 
   visitMapLiteral(MapLiteral node) {
     if (node.modifier != null) {
-      writer.print(node.modifier.lexeme);
-      writer.print(' ');
+      print(node.modifier.lexeme);
+      print(' ');
     }
     visitSuffixed(node.typeArguments, ' ');
-    writer.print('{');
+    print('{');
     visitList(node.entries, ', ');
-    writer.print('}');
+    print('}');
   }
 
   visitMapLiteralEntry(MapLiteralEntry node) {
     visit(node.key);
-    writer.print(' : ');
+    print(' : ');
     visit(node.value);
   }
 
   visitMethodDeclaration(MethodDeclaration node) {
-    emitToken(node.externalKeyword, ' ');
-    emitToken(node.modifierKeyword, ' ');
+    emitToken(node.externalKeyword, suffix: ' ');
+    emitToken(node.modifierKeyword, suffix: ' ');
     visitSuffixed(node.returnType, ' ');
-    emitToken(node.propertyKeyword, ' ');
-    emitToken(node.operatorKeyword, ' ');
+    emitToken(node.propertyKeyword, suffix: ' ');
+    emitToken(node.operatorKeyword, suffix: ' ');
     visit(node.name);
     if (!node.isGetter) {
       visit(node.parameters);
@@ -650,7 +642,7 @@
 
   visitMethodInvocation(MethodInvocation node) {
     if (node.isCascaded) {
-      writer.print('..');
+      print('..');
     } else {
       visitSuffixed(node.target, '.');
     }
@@ -664,107 +656,107 @@
   }
 
   visitNativeClause(NativeClause node) {
-    writer.print('native ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.name);
   }
 
   visitNativeFunctionBody(NativeFunctionBody node) {
-    writer.print('native ');
+    emitToken(node.nativeToken, suffix: ' ');
     visit(node.stringLiteral);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitNullLiteral(NullLiteral node) {
-    writer.print('null');
+    emitToken(node.literal);
   }
 
   visitParenthesizedExpression(ParenthesizedExpression node) {
-    writer.print('(');
+    emitToken(node.leftParenthesis);
     visit(node.expression);
-    writer.print(')');
+    emitToken(node.rightParenthesis);
   }
 
   visitPartDirective(PartDirective node) {
-    writer.print('part ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.uri);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitPartOfDirective(PartOfDirective node) {
-    writer.print('part of ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.libraryName);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitPostfixExpression(PostfixExpression node) {
     visit(node.operand);
-    writer.print(node.operator.lexeme);
+    print(node.operator.lexeme);
   }
 
   visitPrefixedIdentifier(PrefixedIdentifier node) {
     visit(node.prefix);
-    writer.print('.');
+    print('.');
     visit(node.identifier);
   }
 
   visitPrefixExpression(PrefixExpression node) {
-    writer.print(node.operator.lexeme);
+    emitToken(node.operator);
     visit(node.operand);
   }
 
   visitPropertyAccess(PropertyAccess node) {
     if (node.isCascaded) {
-      writer.print('..');
+      print('..');
     } else {
       visit(node.target);
-      writer.print('.');
+      print('.');
     }
     visit(node.propertyName);
   }
 
   visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
-    writer.print('this');
+    emitToken(node.keyword);
     visitPrefixed('.', node.constructorName);
     visit(node.argumentList);
   }
 
   visitRethrowExpression(RethrowExpression node) {
-    writer.print('rethrow');
+    emitToken(node.keyword);
   }
 
   visitReturnStatement(ReturnStatement node) {
     var expression = node.expression;
     if (expression == null) {
-      writer.print('return;');
+      emitToken(node.keyword, minNewlines: 1);
+      emitToken(node.semicolon);
     } else {
-      writer.print('return ');
+      emitToken(node.keyword, suffix: ' ', minNewlines: 1);
       expression.accept(this);
-      writer.print(';');
+      emitToken(node.semicolon);
     }
   }
 
   visitScriptTag(ScriptTag node) {
-    writer.print(node.scriptTag.lexeme);
+    print(node.scriptTag.lexeme);
   }
 
   visitShowCombinator(ShowCombinator node) {
-    writer.print('show ');
+    emitToken(node.keyword, suffix: ' ');
     visitList(node.shownNames, ', ');
   }
 
   visitSimpleFormalParameter(SimpleFormalParameter node) {
-    emitToken(node.keyword, ' ');
+    emitToken(node.keyword, suffix: ' ');
     visitSuffixed(node.type, ' ');
     visit(node.identifier);
   }
 
   visitSimpleIdentifier(SimpleIdentifier node) {
-    emit(node.token);
-//    writer.print(node.token.lexeme);
+    emitToken(node.token);
   }
 
   visitSimpleStringLiteral(SimpleStringLiteral node) {
-    writer.print(node.literal.lexeme);
+    emitToken(node.literal);
   }
 
   visitStringInterpolation(StringInterpolation node) {
@@ -772,35 +764,42 @@
   }
 
   visitSuperConstructorInvocation(SuperConstructorInvocation node) {
-    writer.print('super');
+    emitToken(node.keyword);
     visitPrefixed('.', node.constructorName);
     visit(node.argumentList);
   }
 
   visitSuperExpression(SuperExpression node) {
-    writer.print('super');
+    emitToken(node.keyword);
   }
 
   visitSwitchCase(SwitchCase node) {
     visitSuffixedList(node.labels, ' ', ' ');
-    writer.print('case ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.expression);
-    writer.print(': ');
-    visitList(node.statements, ' ');
+    print(':');
+    indent();
+    visitList(node.statements);
+    unindent();
   }
 
   visitSwitchDefault(SwitchDefault node) {
     visitSuffixedList(node.labels, ' ', ' ');
-    writer.print('default: ');
+    emitToken(node.keyword, suffix: ': ');
     visitList(node.statements, ' ');
   }
 
   visitSwitchStatement(SwitchStatement node) {
-    writer.print('switch (');
+    emitToken(node.keyword);
+    print(' (');
     visit(node.expression);
-    writer.print(') {');
-    visitList(node.members, ' ');
-    writer.print('}');
+    print(') ');
+    emitToken(node.leftBracket);
+    indent();
+    visitList(node.members);
+    unindent();
+    emitToken(node.rightBracket);
+    newline();
   }
 
   visitSymbolLiteral(SymbolLiteral node) {
@@ -808,11 +807,11 @@
   }
 
   visitThisExpression(ThisExpression node) {
-    writer.print('this');
+    emitToken(node.keyword);
   }
 
   visitThrowExpression(ThrowExpression node) {
-    writer.print('throw ');
+    emitToken(node.keyword, suffix: ' ');
     visit(node.expression);
   }
 
@@ -821,16 +820,16 @@
   }
 
   visitTryStatement(TryStatement node) {
-    writer.print('try ');
+    emitToken(node.tryKeyword, suffix: ' ');
     visit(node.body);
     visitPrefixedList(' ', node.catchClauses, ' ');
     visitPrefixed(' finally ', node.finallyClause);
   }
 
   visitTypeArgumentList(TypeArgumentList node) {
-    writer.print('<');
+    emitToken(node.leftBracket);
     visitList(node.arguments, ', ');
-    writer.print('>');
+    emitToken(node.rightBracket);
   }
 
   visitTypeName(TypeName node) {
@@ -844,9 +843,9 @@
   }
 
   visitTypeParameterList(TypeParameterList node) {
-    writer.print('<');
+    emitToken(node.leftBracket);
     visitList(node.typeParameters, ', ');
-    writer.print('>');
+    emitToken(node.rightBracket);
   }
 
   visitVariableDeclaration(VariableDeclaration node) {
@@ -855,25 +854,25 @@
   }
 
   visitVariableDeclarationList(VariableDeclarationList node) {
-    emitToken(node.keyword, ' ');
+    emitToken(node.keyword, suffix: ' ');
     visitSuffixed(node.type, ' ');
     visitList(node.variables, ', ');
   }
 
   visitVariableDeclarationStatement(VariableDeclarationStatement node) {
     visit(node.variables);
-    writer.print(';');
+    emitToken(node.semicolon);
   }
 
   visitWhileStatement(WhileStatement node) {
-    writer.print('while (');
+    emitToken(node.keyword, suffix: ' (');
     visit(node.condition);
-    writer.print(') ');
+    print(') ');
     visit(node.body);
   }
 
   visitWithClause(WithClause node) {
-    writer.print('with ');
+    emitToken(node.withKeyword, suffix: ' ');
     visitList(node.mixinTypes, ', ');
   }
 
@@ -889,7 +888,7 @@
   visitSuffixed(ASTNode node, String suffix) {
     if (node != null) {
       node.accept(this);
-      writer.print(suffix);
+      print(suffix);
     }
   }
 
@@ -897,7 +896,7 @@
   /// it is non-null.
   visitPrefixed(String prefix, ASTNode node) {
     if (node != null) {
-      writer.print(prefix);
+      print(prefix);
       node.accept(this);
     }
   }
@@ -906,36 +905,18 @@
   /// body is not empty.
   visitPrefixedBody(String prefix, FunctionBody body) {
     if (body is! EmptyFunctionBody) {
-      writer.print(prefix);
+      print(prefix);
     }
     visit(body);
   }
 
-  /// Emit the given [token], printing the prefix before the [token]
-  /// if it is non-null.
-  emitPrefixedToken(String prefix, Token token) {
-    if (token != null) {
-      writer.print(prefix);
-      emit(token);
-    }
-  }
-
-  /// Emit the given [token], printing the suffix after the [token]
-  /// node if it is non-null.
-  emitToken(Token token, String suffix) {
-    if (token != null) {
-      emit(token);
-      writer.print(suffix);
-    }
-  }
-
-  /// Print a list of [nodes], separated by the given [separator].
+  /// Print a list of [nodes], optionally separated by the given [separator].
   visitList(NodeList<ASTNode> nodes, [String separator = '']) {
     if (nodes != null) {
       var size = nodes.length;
       for (var i = 0; i < size; i++) {
         if (i > 0) {
-          writer.print(separator);
+          print(separator);
         }
         nodes[i].accept(this);
       }
@@ -949,11 +930,11 @@
       if (size > 0) {
         for (var i = 0; i < size; i++) {
           if (i > 0) {
-            writer.print(separator);
+            print(separator);
           }
           nodes[i].accept(this);
         }
-        writer.print(suffix);
+        print(suffix);
       }
     }
   }
@@ -964,10 +945,10 @@
     if (nodes != null) {
       var size = nodes.length;
       if (size > 0) {
-        writer.print(prefix);
+        print(prefix);
         for (var i = 0; i < size; i++) {
           if (i > 0 && separator != null) {
-            writer.print(separator);
+            print(separator);
           }
           nodes[i].accept(this);
         }
@@ -975,21 +956,60 @@
     }
   }
 
-  /// Emit the given [token], preceeded by any detected newlines or a minimum
-  /// as specified by [min].
-  emit(Token token, {min: 0}) {
+
+  /// Emit the given [token], if it's non-null, preceded by any detected 
+  /// newlines or a minimum as specified by [minNewlines], printing a [prefix] 
+  /// before and a [suffix] after.
+  emitToken(Token token, {String prefix, String suffix, 
+      int minNewlines: 0}) {
+    if (token != null) {
+      print(prefix);
+      emitPrecedingNewlines(token, min: minNewlines);
+      print(token.lexeme);
+      print(suffix);
+    }
+  }
+  
+  /// Print the given [string] to the source writer if it's non-null.
+  print(String string) {
+    if (string != null) {
+      writer.print(string);
+    }
+  }
+  
+  /// Emit a newline.
+  newline() {
+   writer.newline();
+  }
+  
+  /// Emit [n] newlines.
+  newlines(n) {
+   writer.newlines(n);
+  }
+  
+  /// Indent.
+  indent() {
+    writer.indent();
+  }
+  
+  /// Unindent
+  unindent() {
+    writer.unindent();
+  }
+  
+  /// Emit any detected newlines or a minimum as specified by [minNewlines].
+  emitPrecedingNewlines(Token token, {min: 0}) {
     var comment = token.precedingComments;
     var currentToken = comment != null ? comment : token;
-    var newlines = max(min, countNewlinesBetween(previousToken, currentToken));
-    writer.newlines(newlines);
+    var lines = max(min, countNewlinesBetween(previousToken, currentToken));
+    newlines(lines);
     while (comment != null) {
-      writer.print(comment.toString().trim());
-      writer.newline();
+      print(comment.toString().trim());
+      newline();
       comment = comment.next;
     }
 
     previousToken = token;
-    writer.print(token.lexeme);
   }
 
   /// Count the blanks between these two nodes.
@@ -1016,4 +1036,6 @@
     return  currentLine - lastLine;
   }
 
+  String toString() => writer.toString();
+  
 }
\ No newline at end of file
diff --git a/pkg/analyzer_experimental/test/services/formatter_test.dart b/pkg/analyzer_experimental/test/services/formatter_test.dart
index b232cd1..3f21446 100644
--- a/pkg/analyzer_experimental/test/services/formatter_test.dart
+++ b/pkg/analyzer_experimental/test/services/formatter_test.dart
@@ -153,7 +153,7 @@
           '  int b() => 42;\n\n'
           '  int c() => b();\n\n'
           '}\n'
-        );
+      );
     });
 
     test('stmt', () {
@@ -180,9 +180,71 @@
          '} else {\n'
          '  return false;\n'
          '}'
-        );
+      );
     });
 
+    test('stmt (switch)', () {
+      expectStmtFormatsTo(
+        'switch (fruit) {\n'
+        'case "apple":\n'
+        'print("delish");\n'
+        'break;\n'
+        'case "fig":\n'
+        'print("bleh");\n'
+        'break;\n'
+        '}\n',
+        'switch (fruit) {\n'
+        '  case "apple":\n'
+        '    print("delish");\n'
+        '    break;\n'
+        '  case "fig":\n'
+        '    print("bleh");\n'
+        '    break;\n'
+        '}\n'
+      );
+    });
+  
+    test('stmt (generics)', () {
+      expectStmtFormatsTo(
+        'var numbers = <int>[1, 2, (3 + 4)];',
+        'var numbers = <int>[1, 2, (3 + 4)];'
+      );
+    });
+    
+    test('stmt (try/catch)', () {
+      expectStmtFormatsTo(
+        'try {\n'
+        'doSomething();\n'
+        '} catch (e) {\n'
+        'print(e);\n'
+        '}\n',
+        'try {\n'
+        '  doSomething();\n'
+        '} catch (e) {\n'
+        '  print(e);\n'
+        '}\n'
+      );
+    });
+    
+    test('stmt (binary/ternary ops)', () {
+      expectStmtFormatsTo(
+        'var a = 1 + 2 / (3 * -b);',
+        'var a = 1 + 2 / (3 * -b);'
+      );
+      expectStmtFormatsTo(
+        'var c = !condition == a > b;',
+        'var c = !condition == a > b;'
+      );
+      expectStmtFormatsTo(
+        'var d = condition ? b : object.method(a, b, c);',
+        'var d = condition ? b : object.method(a, b, c);'
+      );
+      expectStmtFormatsTo(
+        'var d = obj is! SomeType;',
+        'var d = obj is! SomeType;'
+      );
+    });
+    
     test('initialIndent', () {
       var formatter = new CodeFormatter(
           new FormatterOptions(initialIndentationLevel: 2));
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index 2ffe489..af48a47 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -66,13 +66,13 @@
   ///
   /// This will not emit programming errors from barback itself. Those will be
   /// emitted through the [results] stream's error channel.
-  Stream get errors => _errorsController.stream;
-  final _errorsController = new StreamController.broadcast();
+  Stream<BarbackException> get errors => _errorsController.stream;
+  final _errorsController = new StreamController<BarbackException>.broadcast();
 
   /// The errors that have occurred since the current build started.
   ///
   /// This will be empty if no build is occurring.
-  Queue _accumulatedErrors;
+  Queue<BarbackException> _accumulatedErrors;
 
   /// A future that completes when the currently running build process finishes.
   ///
@@ -188,7 +188,7 @@
       }).then((asset) {
         var controller = _sourceControllerMap[id].setAvailable(asset);
       }).catchError((error) {
-        reportError(error);
+        reportError(new AssetLoadException(id, error));
 
         // TODO(nweiz): propagate error information through asset nodes.
         _sourceControllerMap.remove(id).setRemoved();
@@ -208,7 +208,7 @@
     });
   }
 
-  void reportError(error) {
+  void reportError(BarbackException error) {
     _accumulatedErrors.add(error);
     _errorsController.add(error);
   }
diff --git a/pkg/barback/lib/src/asset_id.dart b/pkg/barback/lib/src/asset_id.dart
index d514a76..d9cef32 100644
--- a/pkg/barback/lib/src/asset_id.dart
+++ b/pkg/barback/lib/src/asset_id.dart
@@ -13,7 +13,7 @@
 final _posix = new pathos.Builder(style: pathos.Style.posix);
 
 /// Identifies an asset within a package.
-class AssetId {
+class AssetId implements Comparable<AssetId> {
   /// The name of the package containing this asset.
   final String package;
 
@@ -73,6 +73,12 @@
 
   int get hashCode => package.hashCode ^ path.hashCode;
 
+  int compareTo(AssetId other) {
+    var packageComp = package.compareTo(other.package);
+    if (packageComp != 0) return packageComp;
+    return path.compareTo(other.path);
+  }
+
   /// Returns a new [AssetId] with the same [package] as this one and with the
   /// [path] extended to include [extension].
   AssetId addExtension(String extension) =>
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index 6e7789a..587f2bd 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -22,6 +22,11 @@
   /// The id of the asset that this node represents.
   final AssetId id;
 
+  /// The transform that created this asset node.
+  ///
+  /// This is `null` for source assets.
+  final TransformNode transform;
+
   /// The current state of the asset node.
   AssetState get state => _state;
   AssetState _state;
@@ -106,10 +111,10 @@
     return onStateChange.firstWhere(test);
   }
 
-  AssetNode._(this.id)
+  AssetNode._(this.id, this.transform)
       : _state = AssetState.DIRTY;
 
-  AssetNode._available(Asset asset)
+  AssetNode._available(Asset asset, this.transform)
       : id = asset.id,
         _asset = asset,
         _state = AssetState.AVAILABLE;
@@ -122,13 +127,13 @@
   final AssetNode node;
 
   /// Creates a controller for a dirty node.
-  AssetNodeController(AssetId id)
-      : node = new AssetNode._(id);
+  AssetNodeController(AssetId id, [TransformNode transform])
+      : node = new AssetNode._(id, transform);
 
   /// Creates a controller for an available node with the given concrete
   /// [asset].
-  AssetNodeController.available(Asset asset)
-      : node = new AssetNode._available(asset);
+  AssetNodeController.available(Asset asset, [TransformNode transform])
+      : node = new AssetNode._available(asset, transform);
 
   /// Marks the node as [AssetState.DIRTY].
   void setDirty() {
diff --git a/pkg/barback/lib/src/build_result.dart b/pkg/barback/lib/src/build_result.dart
index 32ee7c7..89ee681 100644
--- a/pkg/barback/lib/src/build_result.dart
+++ b/pkg/barback/lib/src/build_result.dart
@@ -17,13 +17,13 @@
 /// although individual assets may still have built successfully.
 class BuildResult {
   /// All errors that occurred during the build.
-  final List errors;
+  final Set<BarbackException> errors;
 
   /// `true` if the build succeeded.
   bool get succeeded => errors.isEmpty;
 
-  BuildResult(Iterable errors)
-      : errors = errors.toList();
+  BuildResult(Iterable<BarbackException> errors)
+      : errors = errors.toSet();
 
   /// Creates a build result indicating a successful build.
   ///
diff --git a/pkg/barback/lib/src/errors.dart b/pkg/barback/lib/src/errors.dart
index 9ebca8e..a379ae5 100644
--- a/pkg/barback/lib/src/errors.dart
+++ b/pkg/barback/lib/src/errors.dart
@@ -7,7 +7,10 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:stack_trace/stack_trace.dart';
+
 import 'asset_id.dart';
+import 'transformer.dart';
 
 /// Error thrown when an asset with [id] cannot be found.
 class AssetNotFoundException implements Exception {
@@ -18,32 +21,99 @@
   String toString() => "Could not find asset $id.";
 }
 
-/// Error thrown when two transformers both output an asset with [id].
-class AssetCollisionException implements Exception {
+/// The interface for exceptions from the barback graph or its transformers.
+///
+/// These exceptions are never produced by programming errors in barback.
+abstract class BarbackException implements Exception {}
+
+/// Error thrown when two or more transformers both output an asset with [id].
+class AssetCollisionException implements BarbackException {
+  /// All the transforms that output an asset with [id].
+  final Set<TransformInfo> transforms;
   final AssetId id;
 
-  AssetCollisionException(this.id);
+  AssetCollisionException(Iterable<TransformInfo> transforms, this.id)
+      : transforms = new Set.from(transforms);
 
-  String toString() => "Got collision on asset $id.";
+  String toString() => "Transforms $transforms all emitted asset $id.";
 }
 
 /// Error thrown when a transformer requests an input [id] which cannot be
 /// found.
-class MissingInputException implements Exception {
+class MissingInputException implements BarbackException {
+  /// The transform that requested [id].
+  final TransformInfo transform;
   final AssetId id;
 
-  MissingInputException(this.id);
+  MissingInputException(this.transform, this.id);
 
-  String toString() => "Missing input $id.";
+  String toString() => "Transform $transform tried to load missing input $id.";
 }
 
-/// Error thrown when a transformer outputs an asset with the wrong package
-/// name.
-class InvalidOutputException implements Exception {
-  final String package;
+/// Error thrown when a transformer outputs an asset to a different package than
+/// the primary input's.
+class InvalidOutputException implements BarbackException {
+  /// The transform that output the asset.
+  final TransformInfo transform;
   final AssetId id;
 
-  InvalidOutputException(this.package, this.id);
+  InvalidOutputException(this.transform, this.id);
 
-  String toString() => "Invalid output $id: must be in package $package.";
+  String toString() => "Transform $transform emitted $id, which wasn't in the "
+      "same package (${transform.primaryId.package}).";
+}
+
+/// Error wrapping an exception thrown by a transform.
+class TransformerException implements BarbackException {
+  /// The transform that threw the exception.
+  final TransformInfo transform;
+
+  /// The wrapped exception.
+  final error;
+
+  TransformerException(this.transform, this.error);
+
+  String toString() => "Transform $transform threw error: $error\n" +
+    new Trace.from(getAttachedStackTrace(error)).terse.toString();
+}
+
+/// Error thrown when a source asset [id] fails to load.
+///
+/// This can be thrown either because the source asset was expected to exist and
+/// did not or because reading it failed somehow.
+class AssetLoadException implements BarbackException {
+  final AssetId id;
+
+  /// The wrapped exception.
+  final error;
+
+  AssetLoadException(this.id, this.error);
+
+  String toString() => "Failed to load source asset $id: $error\n"
+      "${new Trace.from(getAttachedStackTrace(error)).terse}";
+}
+
+/// Information about a single transform in the barback graph.
+///
+/// Identifies a single transformation in the barback graph.
+///
+/// A transformation is uniquely identified by the ID of its primary input, and
+/// the transformer that is applied to it.
+class TransformInfo {
+  /// The transformer that's run for this transform.
+  final Transformer transformer;
+
+  /// The id of this transform's primary asset.
+  final AssetId primaryId;
+
+  TransformInfo(this.transformer, this.primaryId);
+
+  bool operator==(other) =>
+      other is TransformInfo &&
+      other.transformer == transformer &&
+      other.primaryId == primaryId;
+
+  int get hashCode => transformer.hashCode ^ primaryId.hashCode;
+
+  String toString() => "$transformer on $primaryId";
 }
diff --git a/pkg/barback/lib/src/package_graph.dart b/pkg/barback/lib/src/package_graph.dart
index c85fdd7..307a870 100644
--- a/pkg/barback/lib/src/package_graph.dart
+++ b/pkg/barback/lib/src/package_graph.dart
@@ -52,8 +52,8 @@
   ///
   /// This will not emit programming errors from barback itself. Those will be
   /// emitted through the [results] stream's error channel.
-  Stream get errors => _errors;
-  Stream _errors;
+  Stream<BarbackException> get errors => _errors;
+  Stream<BarbackException> _errors;
 
   /// Creates a new [PackageGraph] that will transform assets in all packages
   /// made available by [provider].
@@ -74,7 +74,7 @@
 
         // Include all build errors for all cascades. If no cascades have
         // errors, the result will automatically be considered a success.
-        _resultsController.add(new BuildResult(flatten(
+        _resultsController.add(new BuildResult(unionAll(
             _cascadeResults.values.map((result) => result.errors))));
       }, onError: _resultsController.addError);
     }
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index 82ec521..cf817ca 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -5,6 +5,7 @@
 library barback.phase;
 
 import 'dart:async';
+import 'dart:collection';
 
 import 'asset.dart';
 import 'asset_cascade.dart';
@@ -68,11 +69,15 @@
   /// being run on an old version of that asset.
   var _pendingNewInputs = new Map<AssetId, AssetNode>();
 
-  /// The ids of assets that are emitted by transforms in this phase.
+  /// A map of output ids to the asset node outputs for those ids and the
+  /// transforms that produced those asset nodes.
   ///
-  /// This is used to detect collisions where multiple transforms emit the same
-  /// output.
-  final _outputs = new Set<AssetId>();
+  /// Usually there's only one node for a given output id. However, it's
+  /// possible for multiple transformers in this phase to output an asset with
+  /// the same id. In that case, the chronologically first output emitted is
+  /// passed forward. We keep track of the other nodes so that if that output is
+  /// removed, we know which asset to replace it with.
+  final _outputs = new Map<AssetId, Queue<AssetNode>>();
 
   /// A stream that emits an event whenever this phase becomes dirty and needs
   /// to be run.
@@ -310,27 +315,69 @@
         .where((transform) => transform.isDirty).toList();
     if (dirtyTransforms.isEmpty) return null;
 
-    return Future.wait(dirtyTransforms.map((transform) => transform.apply()))
-        .then((allNewOutputs) {
-      var newOutputs = allNewOutputs.reduce((set1, set2) => set1.union(set2));
+    var collisions = new Set<AssetId>();
+    return Future.wait(dirtyTransforms.map((transform) {
+      return transform.apply().then((outputs) {
+        for (var output in outputs) {
+          if (_outputs.containsKey(output.id)) {
+            _outputs[output.id].add(output);
+            collisions.add(output.id);
+          } else {
+            _outputs[output.id] = new Queue<AssetNode>.from([output]);
+            _next.addInput(output);
+          }
 
-      var collisions = new Set<AssetId>();
-      for (var newOutput in newOutputs) {
-        if (_outputs.contains(newOutput.id)) {
-          collisions.add(newOutput.id);
-        } else {
-          _next.addInput(newOutput);
-          _outputs.add(newOutput.id);
-          newOutput.whenRemoved.then((_) => _outputs.remove(newOutput.id));
+          _handleOutputRemoval(output);
         }
-      }
-
+      });
+    })).then((_) {
       // Report collisions in a deterministic order.
       collisions = collisions.toList();
-      collisions.sort((a, b) => a.toString().compareTo(b.toString()));
+      collisions.sort((a, b) => a.compareTo(b));
       for (var collision in collisions) {
-        cascade.reportError(new AssetCollisionException(collision));
-        // TODO(rnystrom): Define what happens after a collision occurs.
+        // Ensure that there's still a collision. It's possible it was resolved
+        // while another transform was running.
+        if (_outputs[collision].length <= 1) continue;
+        cascade.reportError(new AssetCollisionException(
+            _outputs[collision].where((asset) => asset.transform != null)
+                .map((asset) => asset.transform.info),
+            collision));
+      }
+    });
+  }
+
+  /// Properly resolve collisions when [output] is removed.
+  void _handleOutputRemoval(AssetNode output) {
+    output.whenRemoved.then((_) {
+      var assets = _outputs[output.id];
+      if (assets.length == 1) {
+        assert(assets.single == output);
+        _outputs.remove(output.id);
+        return;
+      }
+
+      // If there was more than one asset, we're resolving a collision --
+      // possibly partially.
+      var wasFirst = assets.first == output;
+      assets.remove(output);
+
+      // If this was the first asset, we need to pass the next asset
+      // (chronologically) to the next phase. Pump the event queue first to give
+      // [_next] a chance to handle the removal of its input before getting a
+      // new input.
+      if (wasFirst) {
+        newFuture(() => _next.addInput(assets.first));
+      }
+
+      // If there's still a collision, report it. This lets the user know
+      // if they've successfully resolved the collision or not.
+      if (assets.length > 1) {
+        // Pump the event queue to ensure that the removal of the input triggers
+        // a new build to which we can attach the error.
+        newFuture(() => cascade.reportError(new AssetCollisionException(
+            assets.where((asset) => asset.transform != null)
+                .map((asset) => asset.transform.info),
+            output.id)));
       }
     });
   }
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
index a7241ae..1d3d1dd 100644
--- a/pkg/barback/lib/src/transform_node.dart
+++ b/pkg/barback/lib/src/transform_node.dart
@@ -64,6 +64,12 @@
     });
   }
 
+  /// The [TransformInfo] describing this node.
+  ///
+  /// [TransformInfo] is the publicly-visible representation of a transform
+  /// node.
+  TransformInfo get info => new TransformInfo(transformer, primary.id);
+
   /// Marks this transform as removed.
   ///
   /// This causes all of the transform's outputs to be marked as removed as
@@ -98,6 +104,8 @@
   /// Returns a set of asset nodes representing the outputs from this transform
   /// that weren't emitted last time it was run.
   Future<Set<AssetNode>> apply() {
+    assert(!_onDirtyController.isClosed);
+
     var newOutputs = new AssetSet();
     var transform = createTransform(this, newOutputs);
 
@@ -114,6 +122,10 @@
       // it.
       if (_isDirty) return;
 
+      if (error is! MissingInputException) {
+        error = new TransformerException(info, error);
+      }
+
       // Catch all transformer errors and pipe them to the results stream.
       // This is so a broken transformer doesn't take down the whole graph.
       phase.cascade.reportError(error);
@@ -136,7 +148,7 @@
       // Throw if the input isn't found. This ensures the transformer's apply
       // is exited. We'll then catch this and report it through the proper
       // results stream.
-      if (node == null) throw new MissingInputException(id);
+      if (node == null) throw new MissingInputException(info, id);
 
       // If the asset node is found, wait until its contents are actually
       // available before we return them.
@@ -149,7 +161,7 @@
         if (error is! AssetNotFoundException || error.id != id) throw error;
         // If the node was removed before it could be loaded, treat it as though
         // it never existed and throw a MissingInputException.
-        throw new MissingInputException(id);
+        throw new MissingInputException(info, id);
       });
     });
   }
@@ -165,8 +177,7 @@
     for (var id in invalidIds) {
       newOutputs.removeId(id);
       // TODO(nweiz): report this as a warning rather than a failing error.
-      phase.cascade.reportError(
-          new InvalidOutputException(phase.cascade.package, id));
+      phase.cascade.reportError(new InvalidOutputException(info, id));
     }
 
     // Remove outputs that used to exist but don't anymore.
@@ -182,7 +193,7 @@
       if (controller != null) {
         controller.setAvailable(asset);
       } else {
-        var controller = new AssetNodeController.available(asset);
+        var controller = new AssetNodeController.available(asset, this);
         _outputControllers[asset.id] = controller;
         brandNewOutputs.add(controller.node);
       }
diff --git a/pkg/barback/lib/src/utils.dart b/pkg/barback/lib/src/utils.dart
index 7529fa9..bee6084 100644
--- a/pkg/barback/lib/src/utils.dart
+++ b/pkg/barback/lib/src/utils.dart
@@ -6,6 +6,23 @@
 
 import 'dart:async';
 
+/// A pair of values.
+class Pair<E, F> {
+  E first;
+  F last;
+
+  Pair(this.first, this.last);
+
+  String toString() => '($first, $last)';
+
+  bool operator==(other) {
+    if (other is! Pair) return false;
+    return other.first == first && other.last == last;
+  }
+
+  int get hashCode => first.hashCode ^ last.hashCode;
+}
+
 /// Converts a number in the range [0-255] to a two digit hex string.
 ///
 /// For example, given `255`, returns `ff`.
@@ -46,6 +63,10 @@
   return result;
 }
 
+/// Returns the union of all elements in each set in [sets].
+Set unionAll(Iterable<Set> sets) =>
+  sets.fold(new Set(), (union, set) => union.union(set));
+
 /// Passes each key/value pair in [map] to [fn] and returns a new [Map] whose
 /// values are the return values of [fn].
 Map mapMapValues(Map map, fn(key, value)) =>
diff --git a/pkg/barback/test/package_graph/errors_test.dart b/pkg/barback/test/package_graph/errors_test.dart
index 6e7f2fb..46ff289 100644
--- a/pkg/barback/test/package_graph/errors_test.dart
+++ b/pkg/barback/test/package_graph/errors_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 
 import 'package:barback/barback.dart';
+import 'package:barback/src/utils.dart';
 import 'package:scheduled_test/scheduled_test.dart';
 
 import '../utils.dart';
@@ -61,7 +62,10 @@
     initGraph(["app|known.txt"]);
     updateSources(["app|unknown.txt"]);
 
-    buildShouldFail([isAssetNotFoundException("app|unknown.txt")]);
+    buildShouldFail([
+      isAssetLoadException("app|unknown.txt",
+          isAssetNotFoundException("app|unknown.txt"))
+    ]);
   });
 
   test("reports missing input errors in results", () {
@@ -81,7 +85,7 @@
     });
 
     updateSources(["app|foo.txt"]);
-    buildShouldFail([isInvalidOutputException("app", "wrong|foo.txt")]);
+    buildShouldFail([isInvalidOutputException("wrong|foo.txt")]);
   });
 
   test("fails if a non-primary input is removed", () {
@@ -110,7 +114,7 @@
 
     updateSources(["app|foo.txt"]);
     expectNoAsset("app|foo.out");
-    buildShouldFail([equals(BadTransformer.ERROR)]);
+    buildShouldFail([isTransformerException(equals(BadTransformer.ERROR))]);
   });
 
   test("doesn't yield a source if a transform fails on it", () {
@@ -127,7 +131,7 @@
 
     updateSources(["app|foo.txt"]);
     // Note: No asset requests here.
-    buildShouldFail([equals(BadTransformer.ERROR)]);
+    buildShouldFail([isTransformerException(equals(BadTransformer.ERROR))]);
   });
 
   test("discards outputs from failed transforms", () {
@@ -145,7 +149,7 @@
 
     updateSources(["pkg1|foo.txt", "pkg2|foo.txt"]);
     expectAsset("pkg2|foo.txt", "foo");
-    buildShouldFail([equals(BadTransformer.ERROR)]);
+    buildShouldFail([isTransformerException(equals(BadTransformer.ERROR))]);
   });
 
   test("emits multiple failures if multiple packages fail", () {
@@ -156,8 +160,8 @@
 
     updateSources(["pkg1|foo.txt", "pkg2|foo.txt"]);
     buildShouldFail([
-      equals(BadTransformer.ERROR),
-      equals(BadTransformer.ERROR)
+      isTransformerException(equals(BadTransformer.ERROR)),
+      isTransformerException(equals(BadTransformer.ERROR))
     ]);
   });
 
@@ -167,6 +171,117 @@
     setAssetError("app|foo.txt");
     updateSources(["app|foo.txt"]);
     expectNoAsset("app|foo.txt");
-    buildShouldFail([isMockLoadException("app|foo.txt")]);
+    buildShouldFail([
+      isAssetLoadException("app|foo.txt", isMockLoadException("app|foo.txt"))
+    ]);
+  });
+
+  test("a collision returns the first-produced output", () {
+    var rewrite1 = new RewriteTransformer("one", "out");
+    var rewrite2 = new RewriteTransformer("two", "out");
+    initGraph({
+      "app|foo.one": "one",
+      "app|foo.two": "two"
+    }, {"app": [[rewrite1, rewrite2]]});
+
+    rewrite1.pauseApply();
+    updateSources(["app|foo.one", "app|foo.two"]);
+    // Wait long enough to ensure that rewrite2 has completed.
+    schedule(pumpEventQueue);
+
+    rewrite1.resumeApply();
+    expectAsset("app|foo.out", "two.out");
+    buildShouldFail([isAssetCollisionException("app|foo.out")]);
+
+    // Even after the collision is discovered, the first-produced output should
+    // be returned.
+    expectAsset("app|foo.out", "two.out");
+
+    // Even if the other output is updated more recently, the first output
+    // should continue to take precedence.
+    updateSources(["app|foo.one"]);
+    expectAsset("app|foo.out", "two.out");
+  });
+
+  test("a collision that is later resolved produces an output", () {
+    initGraph({
+      "app|foo.one": "one",
+      "app|foo.two": "two"
+    }, {"app": [
+      [
+        new RewriteTransformer("one", "out"),
+        new RewriteTransformer("two", "out")
+      ]
+    ]});
+
+    updateSources(["app|foo.one"]);
+    expectAsset("app|foo.out", "one.out");
+    buildShouldSucceed();
+
+    updateSources(["app|foo.two"]);
+    expectAsset("app|foo.out", "one.out");
+    buildShouldFail([isAssetCollisionException("app|foo.out")]);
+
+    removeSources(["app|foo.one"]);
+    expectAsset("app|foo.out", "two.out");
+    buildShouldSucceed();
+  });
+
+  test("a collision that is later resolved runs transforms", () {
+    initGraph({
+      "app|foo.one": "one",
+      "app|foo.two": "two"
+    }, {"app": [
+      [
+        new RewriteTransformer("one", "mid"),
+        new RewriteTransformer("two", "mid")
+      ],
+      [new RewriteTransformer("mid", "out")]
+    ]});
+
+    updateSources(["app|foo.one"]);
+    expectAsset("app|foo.out", "one.mid.out");
+    buildShouldSucceed();
+
+    updateSources(["app|foo.two"]);
+    expectAsset("app|foo.out", "one.mid.out");
+    buildShouldFail([isAssetCollisionException("app|foo.mid")]);
+
+    removeSources(["app|foo.one"]);
+    expectAsset("app|foo.out", "two.mid.out");
+    buildShouldSucceed();
+  });
+
+  test("a collision that is partially resolved returns the second completed "
+      "output", () {
+    var rewrite1 = new RewriteTransformer("one", "out");
+    var rewrite2 = new RewriteTransformer("two", "out");
+    var rewrite3 = new RewriteTransformer("three", "out");
+    initGraph({
+      "app|foo.one": "one",
+      "app|foo.two": "two",
+      "app|foo.three": "three"
+    }, {"app": [[rewrite1, rewrite2, rewrite3]]});
+
+    // Make rewrite3 the most-recently-completed transformer from the first run.
+    rewrite2.pauseApply();
+    rewrite3.pauseApply();
+    updateSources(["app|foo.one", "app|foo.two", "app|foo.three"]);
+    schedule(pumpEventQueue);
+    rewrite2.resumeApply();
+    schedule(pumpEventQueue);
+    rewrite3.resumeApply();
+    buildShouldFail([isAssetCollisionException("app|foo.out")]);
+
+    // Then update rewrite3 in a separate build. rewrite2 should still be the
+    // next version of foo.out in line.
+    // TODO(nweiz): Should this emit a collision error as well? Or should they
+    // only be emitted when a file is added or removed?
+    updateSources(["app|foo.three"]);
+    buildShouldSucceed();
+
+    removeSources(["app|foo.one"]);
+    expectAsset("app|foo.out", "two.out");
+    buildShouldFail([isAssetCollisionException("app|foo.out")]);
   });
 }
diff --git a/pkg/barback/test/utils.dart b/pkg/barback/test/utils.dart
index 1de4ac9..99a7ec1 100644
--- a/pkg/barback/test/utils.dart
+++ b/pkg/barback/test/utils.dart
@@ -260,16 +260,32 @@
       predicate((error) => error.id == id, 'id == $name'));
 }
 
-/// Returns a matcher for an [InvalidOutputException] with the given id and
-/// package name.
-Matcher isInvalidOutputException(String package, String name) {
+/// Returns a matcher for an [InvalidOutputException] with the given id.
+Matcher isInvalidOutputException(String name) {
   var id = new AssetId.parse(name);
   return allOf(
       new isInstanceOf<InvalidOutputException>(),
-      predicate((error) => error.package == package, 'package is $package'),
       predicate((error) => error.id == id, 'id == $name'));
 }
 
+/// Returns a matcher for an [AssetLoadException] with the given id and a
+/// wrapped error that matches [error].
+Matcher isAssetLoadException(String name, error) {
+  var id = new AssetId.parse(name);
+  return allOf(
+      new isInstanceOf<AssetLoadException>(),
+      transform((error) => error.id, equals(id), 'id'),
+      transform((error) => error.error, wrapMatcher(error), 'error'));
+}
+
+/// Returns a matcher for a [TransformerException] with a wrapped error that
+/// matches [error].
+Matcher isTransformerException(error) {
+  return allOf(
+      new isInstanceOf<TransformerException>(),
+      transform((error) => error.error, wrapMatcher(error), 'error'));
+}
+
 /// Returns a matcher for a [MockLoadException] with the given [id].
 Matcher isMockLoadException(String name) {
   var id = new AssetId.parse(name);
@@ -278,6 +294,28 @@
       predicate((error) => error.id == id, 'id == $name'));
 }
 
+/// Returns a matcher that runs [transformation] on its input, then matches
+/// the output against [matcher].
+///
+/// [description] should be a noun phrase that describes the relation of the
+/// output of [transformation] to its input.
+Matcher transform(transformation(value), matcher, String description) =>
+  new _TransformMatcher(transformation, wrapMatcher(matcher), description);
+
+class _TransformMatcher extends Matcher {
+  final Function _transformation;
+  final Matcher _matcher;
+  final String _description;
+
+  _TransformMatcher(this._transformation, this._matcher, this._description);
+
+  bool matches(item, Map matchState) =>
+    _matcher.matches(_transformation(item), matchState);
+
+  Description describe(Description description) =>
+    description.add(_description).add(' ').addDescriptionOf(_matcher);
+}
+
 /// Asserts that [future] shouldn't complete until after [delay] completes.
 ///
 /// Once [delay] completes, the output of [future] is ignored, even if it's an
diff --git a/pkg/browser/lib/dart.js b/pkg/browser/lib/dart.js
index 48cd8ad..e14bfbb 100644
--- a/pkg/browser/lib/dart.js
+++ b/pkg/browser/lib/dart.js
@@ -11,28 +11,27 @@
   // TODO:
   // - Support in-browser compilation.
   // - Handle inline Dart scripts.
-  window.addEventListener("DOMContentLoaded", function (e) {
-    // Fall back to compiled JS. Run through all the scripts and
-    // replace them if they have a type that indicate that they source
-    // in Dart code.
-    //
-    //   <script type="application/dart" src="..."></script>
-    //
-    var scripts = document.getElementsByTagName("script");
-    var length = scripts.length;
-    for (var i = 0; i < length; ++i) {
-      if (scripts[i].type == "application/dart") {
-        // Remap foo.dart to foo.dart.js.
-        if (scripts[i].src && scripts[i].src != '') {
-          var script = document.createElement('script');
-          script.src = scripts[i].src.replace(/\.dart(?=\?|$)/, '.dart.js');
-          var parent = scripts[i].parentNode;
-          // TODO(vsm): Find a solution for issue 8455 that works with more
-          // than one script.
-          document.currentScript = script;
-          parent.replaceChild(script, scripts[i]);
-        }
+
+  // Fall back to compiled JS. Run through all the scripts and
+  // replace them if they have a type that indicate that they source
+  // in Dart code.
+  //
+  //   <script type="application/dart" src="..."></script>
+  //
+  var scripts = document.getElementsByTagName("script");
+  var length = scripts.length;
+  for (var i = 0; i < length; ++i) {
+    if (scripts[i].type == "application/dart") {
+      // Remap foo.dart to foo.dart.js.
+      if (scripts[i].src && scripts[i].src != '') {
+        var script = document.createElement('script');
+        script.src = scripts[i].src.replace(/\.dart(?=\?|$)/, '.dart.js');
+        var parent = scripts[i].parentNode;
+        // TODO(vsm): Find a solution for issue 8455 that works with more
+        // than one script.
+        document.currentScript = script;
+        parent.replaceChild(script, scripts[i]);
       }
     }
-  }, false);
+  }
 }
diff --git a/pkg/csslib/README.md b/pkg/csslib/README.md
new file mode 100644
index 0000000..b84dae4
--- /dev/null
+++ b/pkg/csslib/README.md
@@ -0,0 +1,84 @@
+csslib in Pure Dart
+===================
+
+This is a pure [Dart][dart] [CSS parser][cssparse]. Since it's 100%
+Dart you can use it safely from a script or server side app.
+
+[![Build Status](https://drone.io/github.com/dart-lang/csslib/status.png)](https://drone.io/github.com/dart-lang/csslib/latest)
+
+Installation
+------------
+
+Add this to your `pubspec.yaml` (or create it):
+```yaml
+dependencies:
+  csslib: any
+```
+Then run the [Pub Package Manager][pub] (comes with the Dart SDK):
+
+    pub install
+
+Usage
+-----
+
+Parsing CSS is easy!
+```dart
+import 'package:csslib/parser.dart' show parse;
+import 'package:csslib/css.dart';
+
+main() {
+  var stylesheet = parse(
+      '.foo { color: red; left: 20px; top: 20px; width: 100px; height:200px }');
+  print(stylesheet.toString());
+}
+```
+
+You can pass a String or list of bytes to `parse`.
+
+
+Updating
+--------
+
+You can upgrade the library with:
+
+    pub update
+
+Disclaimer: the APIs are not finished. Updating may break your code. If that
+happens, you can check the
+[commit log](https://github.com/dart-lang/csslib/commits/master), to figure
+out what the change was.
+
+If you want to avoid breakage, you can also put the version constraint in your
+`pubspec.yaml` in place of the word `any`.
+
+Running Tests
+-------------
+
+All tests (both canary and suite) should be passing.  Canary are quick test
+verifies that basic CSS is working.  The suite tests are a comprehensive set of
+~11,000 tests.
+
+```bash
+export DART_SDK=path/to/dart/sdk
+
+# Make sure dependencies are installed
+pub install
+
+# Run command both canary and the suite tests
+test/run.sh
+```
+
+  Run only the canary test:
+
+```bash
+ test/run.sh canary
+```
+
+  Run only the suite tests:
+
+```bash
+ test/run.sh suite
+```
+
+[dart]: http://www.dartlang.org/
+[pub]: http://www.dartlang.org/docs/pub-package-manager/
diff --git a/pkg/csslib/bin/css.dart b/pkg/csslib/bin/css.dart
new file mode 100644
index 0000000..08f2930
--- /dev/null
+++ b/pkg/csslib/bin/css.dart
@@ -0,0 +1,8 @@
+#!/usr/bin/env dart
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/css.dart' as css;
+
+void main() => css.main();
diff --git a/pkg/csslib/example/call_parser.dart b/pkg/csslib/example/call_parser.dart
new file mode 100644
index 0000000..6271057
--- /dev/null
+++ b/pkg/csslib/example/call_parser.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+
+import 'package:csslib/parser.dart' as css;
+import 'package:csslib/visitor.dart';
+
+/**
+ * Spin-up CSS parser in checked mode to detect any problematic CSS.  Normally,
+ * CSS will allow any property/value pairs regardless of validity; all of our
+ * tests (by default) will ensure that the CSS is really valid.
+ */
+StyleSheet parseCss(String cssInput, {List errors, List opts}) =>
+    css.parse(cssInput, errors: errors, options: opts == null ?
+        ['--no-colors', '--checked', '--warnings_as_errors', 'memory'] : opts);
+
+// Pretty printer for CSS.
+var emitCss = new CssPrinter();
+String prettyPrint(StyleSheet ss) =>
+    (emitCss..visitTree(ss, pretty: true)).toString();
+
+main() {
+  var errors = [];
+
+  // Parse a simple stylesheet.
+  print('1. Good CSS, parsed CSS emitted:');
+  print('   =============================');
+  var stylesheet = parseCss(
+    '@import "support/at-charset-019.css"; div { color: red; }'
+    'button[type] { background-color: red; }'
+    '.foo { '
+      'color: red; left: 20px; top: 20px; width: 100px; height:200px'
+    '}'
+    '#div {'
+      'color : #00F578; border-color: #878787;'
+    '}', errors: errors);
+
+  if (!errors.isEmpty) {
+    print("Got ${errors.length} errors.\n");
+    for (var error in errors) {
+      print(error);
+    }
+  } else {
+    print(prettyPrint(stylesheet));
+  }
+
+  // Parse a stylesheet with errors
+  print('2. Catch severe syntax errors:');
+  print('   ===========================');
+  var stylesheetError = parseCss(
+    '.foo #%^&*asdf{ '
+      'color: red; left: 20px; top: 20px; width: 100px; height:200px'
+    '}', errors: errors);
+
+  if (!errors.isEmpty) {
+    print("Got ${errors.length} errors.\n");
+    for (var error in errors) {
+      print(error);
+    }
+  } else {
+    print(stylesheetError.toString());
+  }
+
+  // Parse a stylesheet that warns (checks) problematic CSS.
+  print('3. Detect CSS problem with checking on:');
+  print('   ===================================');
+  stylesheetError = parseCss( '# div1 { color: red; }', errors: errors);
+
+  if (!errors.isEmpty) {
+    print("Detected ${errors.length} problem in checked mode.\n");
+    for (var error in errors) {
+      print(error);
+    }
+  } else {
+    print(stylesheetError.toString());
+  }
+
+  // Parse a CSS selector.
+  print('4. Parse a selector only:');
+  print('   ======================');
+  var selectorAst = css.selector('#div .foo', errors: errors);
+  if (!errors.isEmpty) {
+    print("Got ${errors.length} errors.\n");
+    for (var error in errors) {
+      print(error);
+    }
+  } else {
+    print(prettyPrint(selectorAst));
+  }
+
+}
diff --git a/pkg/csslib/example/call_parser.html b/pkg/csslib/example/call_parser.html
new file mode 100644
index 0000000..8dc02e4
--- /dev/null
+++ b/pkg/csslib/example/call_parser.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Call CSS Parser from Browser (Dart2JS and Dartium)</title>
+  </head>
+  <body>
+    <h1>Dartium/Dart2JS Test</h1>
+    <script type="application/dart" src="call_parser.dart"></script>
+    <script src="packages/browser/dart.js"></script>
+  </body>
+</html>
diff --git a/pkg/csslib/example/test.css b/pkg/csslib/example/test.css
new file mode 100644
index 0000000..42aa048
--- /dev/null
+++ b/pkg/csslib/example/test.css
@@ -0,0 +1,6 @@
+.foo #abc {
+  color: red;
+  width: 300px;
+  left: 50px;
+  right: 50px;
+}
\ No newline at end of file
diff --git a/pkg/csslib/lib/css.dart b/pkg/csslib/lib/css.dart
new file mode 100644
index 0000000..ebfc675
--- /dev/null
+++ b/pkg/csslib/lib/css.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library css;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:io';
+import 'dart:math' as Math;
+
+import 'package:path/path.dart' as path;
+import 'package:source_maps/span.dart' show SourceFile;
+
+import 'parser.dart';
+import 'visitor.dart';
+import 'src/messages.dart';
+import 'src/options.dart';
+
+void main() {
+  // TODO(jmesserly): fix this to return a proper exit code
+  var options = PreprocessorOptions.parse(new Options().arguments);
+  if (options == null) return;
+
+  messages = new Messages(options: options);
+
+  _time('Total time spent on ${options.inputFile}', () {
+    _compile(options.inputFile, options.verbose);
+  }, true);
+}
+
+void _compile(String inputPath, bool verbose) {
+  var ext = path.extension(inputPath);
+  if (ext != '.css' && ext != '.scss') {
+    messages.error("Please provide a CSS/Sass file", null);
+    return;
+  }
+  try {
+    // Read the file.
+    var filename = path.basename(inputPath);
+    var contents = new File(inputPath).readAsStringSync();
+    var file = new SourceFile.text(inputPath, contents);
+
+    // Parse the CSS.
+    var tree = _time('Parse $filename',
+        () => new Parser(file, contents).parse(), verbose);
+
+    _time('Analyzer $filename',
+        () => new Analyzer([tree], messages), verbose).run();
+
+    // Emit the processed CSS.
+    var emitter = new CssPrinter();
+    _time('Codegen $filename',
+        () => emitter.visitTree(tree, pretty: true), verbose);
+
+    // Write the contents to a file.
+    var outPath = path.join(path.dirname(inputPath), '_$filename');
+    new File(outPath).writeAsStringSync(emitter.toString());
+  } catch (e) {
+    messages.error('error processing $inputPath. Original message:\n $e', null);
+  }
+}
+
+_time(String message, callback(), bool printTime) {
+  if (!printTime) return callback();
+  final watch = new Stopwatch();
+  watch.start();
+  var result = callback();
+  watch.stop();
+  final duration = watch.elapsedMilliseconds;
+  _printMessage(message, duration);
+  return result;
+}
+
+void _printMessage(String message, int duration) {
+  var buf = new StringBuffer();
+  buf.write(message);
+  for (int i = message.length; i < 60; i++) buf.write(' ');
+  buf.write(' -- ');
+  if (duration < 10) buf.write(' ');
+  if (duration < 100) buf.write(' ');
+  buf..write(duration)..write(' ms');
+  print(buf.toString());
+}
diff --git a/pkg/csslib/lib/parser.dart b/pkg/csslib/lib/parser.dart
new file mode 100644
index 0000000..a1cd715
--- /dev/null
+++ b/pkg/csslib/lib/parser.dart
@@ -0,0 +1,2402 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library csslib.parser;
+
+import 'dart:math' as math;
+
+import 'package:source_maps/span.dart' show SourceFile, Span, FileSpan;
+
+import "visitor.dart";
+import 'src/messages.dart';
+import 'src/options.dart';
+
+part 'src/analyzer.dart';
+part 'src/property.dart';
+part 'src/token.dart';
+part 'src/tokenizer_base.dart';
+part 'src/tokenizer.dart';
+part 'src/tokenkind.dart';
+
+
+/** Used for parser lookup ahead (used for nested selectors Less support). */
+class ParserState extends TokenizerState {
+  final Token peekToken;
+  final Token previousToken;
+
+  ParserState(this.peekToken, this.previousToken, Tokenizer tokenizer)
+      : super(tokenizer);
+}
+
+void _createMessages({List errors, List options}) {
+  if (errors == null) errors = [];
+
+  if (options == null) {
+    options = ['--no-colors', 'memory'];
+  }
+  var opt = PreprocessorOptions.parse(options);
+  messages = new Messages(options: opt, printHandler: errors.add);
+}
+
+/** CSS checked mode enabled. */
+bool get isChecked => messages.options.checked;
+
+// TODO(terry): Remove nested name parameter.
+/** Parse and analyze the CSS file. */
+StyleSheet compile(var input, {List errors, List options, bool nested: true}) {
+  var source = _inputAsString(input);
+
+  _createMessages(errors: errors, options: options);
+
+  var file = new SourceFile.text(null, source);
+
+  var tree = new Parser(file, source).parse();
+
+  analyze([tree], errors: errors, options: options);
+
+  return tree;
+}
+
+/** Analyze the CSS file. */
+void analyze(List<StyleSheet> styleSheets,  {List errors, List options}) {
+  _createMessages(errors: errors, options: options);
+  new Analyzer(styleSheets, messages).run();
+}
+
+/**
+ * Parse the [input] CSS stylesheet into a tree. The [input] can be a [String],
+ * or [List<int>] of bytes and returns a [StyleSheet] AST.  The optional
+ * [errors] list will contain each error/warning as a [Message].
+ */
+StyleSheet parse(var input, {List errors, List options}) {
+  var source = _inputAsString(input);
+
+  _createMessages(errors: errors, options: options);
+
+  var file = new SourceFile.text(null, source);
+
+  return new Parser(file, source).parse();
+}
+
+/**
+ * Parse the [input] CSS selector into a tree. The [input] can be a [String],
+ * or [List<int>] of bytes and returns a [StyleSheet] AST.  The optional
+ * [errors] list will contain each error/warning as a [Message].
+ */
+StyleSheet selector(var input, {List errors}) {
+  var source = _inputAsString(input);
+
+  _createMessages(errors: errors);
+
+  var file = new SourceFile.text(null, source);
+
+  return new Parser(file, source).parseSelector();
+}
+
+String _inputAsString(var input) {
+  String source;
+
+  if (input is String) {
+    source = input;
+  } else if (input is List<int>) {
+    // TODO(terry): The parse function needs an "encoding" argument and will
+    //              default to whatever encoding CSS defaults to.
+    //
+    // Here's some info about CSS encodings:
+    // http://www.w3.org/International/questions/qa-css-charset.en.php
+    //
+    // As JMesserly suggests it will probably need a "preparser" html5lib
+    // (encoding_parser.dart) that interprets the bytes as ASCII and scans for
+    // @charset. But for now an "encoding" argument would work.  Often the
+    // HTTP header will indicate the correct encoding.
+    //
+    // See encoding helpers at: package:html5lib/lib/src/char_encodings.dart
+    // These helpers can decode in different formats given an encoding name
+    // (mostly unicode, ascii, windows-1252 which is html5 default encoding).
+    source = new String.fromCharCodes(input);
+  } else {
+    // TODO(terry): Support RandomAccessFile using console.
+    throw new ArgumentError("'source' must be a String or "
+        "List<int> (of bytes). RandomAccessFile not supported from this "
+        "simple interface");
+  }
+
+  return source;
+}
+
+/** A simple recursive descent parser for CSS. */
+class Parser {
+  Tokenizer tokenizer;
+
+  /** Base url of CSS file. */
+  final String _baseUrl;
+
+  /**
+   * File containing the source being parsed, used to report errors with
+   * source-span locations.
+   */
+  final SourceFile file;
+
+  Token _previousToken;
+  Token _peekToken;
+
+  Parser(SourceFile file, String text, {int start: 0, String baseUrl})
+      : this.file = file,
+        _baseUrl = baseUrl,
+        tokenizer = new Tokenizer(file, text, true, start) {
+    _peekToken = tokenizer.next();
+  }
+
+  /** Main entry point for parsing an entire CSS file. */
+  StyleSheet parse() {
+    List<TreeNode> productions = [];
+
+    int start = _peekToken.start;
+    while (!_maybeEat(TokenKind.END_OF_FILE) && !_peekKind(TokenKind.RBRACE)) {
+      // TODO(terry): Need to handle charset.
+      var directive = processDirective();
+      if (directive != null) {
+        productions.add(directive);
+        _maybeEat(TokenKind.SEMICOLON);
+      } else {
+        RuleSet ruleset = processRuleSet();
+        if (ruleset != null) {
+          productions.add(ruleset);
+        } else {
+          break;
+        }
+      }
+    }
+
+    checkEndOfFile();
+
+    return new StyleSheet(productions, _makeSpan(start));
+  }
+
+  /** Main entry point for parsing a simple selector sequence. */
+  StyleSheet parseSelector() {
+    List<TreeNode> productions = [];
+
+    int start = _peekToken.start;
+    while (!_maybeEat(TokenKind.END_OF_FILE) && !_peekKind(TokenKind.RBRACE)) {
+      var selector = processSelector();
+      if (selector != null) {
+        productions.add(selector);
+      }
+    }
+
+    checkEndOfFile();
+
+    return new StyleSheet.selector(productions, _makeSpan(start));
+  }
+
+  /** Generate an error if [file] has not been completely consumed. */
+  void checkEndOfFile() {
+    if (!(_peekKind(TokenKind.END_OF_FILE) ||
+        _peekKind(TokenKind.INCOMPLETE_COMMENT))) {
+      _error('premature end of file unknown CSS', _peekToken.span);
+    }
+  }
+
+  /** Guard to break out of parser when an unexpected end of file is found. */
+  // TODO(jimhug): Failure to call this method can lead to inifinite parser
+  //   loops.  Consider embracing exceptions for more errors to reduce
+  //   the danger here.
+  bool isPrematureEndOfFile() {
+    if (_maybeEat(TokenKind.END_OF_FILE)) {
+      _error('unexpected end of file', _peekToken.span);
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  // Basic support methods
+  ///////////////////////////////////////////////////////////////////
+  int _peek() {
+    return _peekToken.kind;
+  }
+
+  Token _next({unicodeRange : false}) {
+    _previousToken = _peekToken;
+    _peekToken = tokenizer.next(unicodeRange: unicodeRange);
+    return _previousToken;
+  }
+
+  bool _peekKind(int kind) {
+    return _peekToken.kind == kind;
+  }
+
+  /* Is the next token a legal identifier?  This includes pseudo-keywords. */
+  bool _peekIdentifier() {
+    return TokenKind.isIdentifier(_peekToken.kind);
+  }
+
+  /** Marks the parser/tokenizer look ahead to support Less nested selectors. */
+  ParserState get _mark =>
+      new ParserState(_peekToken, _previousToken, tokenizer);
+
+  /** Restores the parser/tokenizer state to state remembered by _mark. */
+  void _restore(ParserState markedData) {
+    tokenizer.restore(markedData);
+    _peekToken = markedData.peekToken;
+    _previousToken = markedData.previousToken;
+  }
+
+  bool _maybeEat(int kind, {unicodeRange : false}) {
+    if (_peekToken.kind == kind) {
+      _previousToken = _peekToken;
+      _peekToken = tokenizer.next(unicodeRange: unicodeRange);
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  void _eat(int kind, {unicodeRange : false}) {
+    if (!_maybeEat(kind, unicodeRange: unicodeRange)) {
+      _errorExpected(TokenKind.kindToString(kind));
+    }
+  }
+
+  void _eatSemicolon() {
+    _eat(TokenKind.SEMICOLON);
+  }
+
+  void _errorExpected(String expected) {
+    var tok = _next();
+    var message;
+    try {
+      message = 'expected $expected, but found $tok';
+    } catch (e) {
+      message = 'parsing error expected $expected';
+    }
+    _error(message, tok.span);
+  }
+
+  void _error(String message, Span location) {
+    if (location == null) {
+      location = _peekToken.span;
+    }
+    messages.error(message, location);
+  }
+
+  void _warning(String message, Span location) {
+    if (location == null) {
+      location = _peekToken.span;
+    }
+    messages.warning(message, location);
+  }
+
+  Span _makeSpan(int start) {
+    // TODO(terry): there are places where we are creating spans before we eat
+    // the tokens, so using _previousToken.end is not always valid.
+    var end = _previousToken != null && _previousToken.end >= start
+        ? _previousToken.end : _peekToken.end;
+    return file.span(start, end);
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  // Top level productions
+  ///////////////////////////////////////////////////////////////////
+
+  /**
+   * The media_query_list production below replaces the media_list production
+   * from CSS2 the new grammar is:
+   *
+   *   media_query_list
+   *    : S* [media_query [ ',' S* media_query ]* ]?
+   *   media_query
+   *    : [ONLY | NOT]? S* media_type S* [ AND S* expression ]*
+   *    | expression [ AND S* expression ]*
+   *   media_type
+   *    : IDENT
+   *   expression
+   *    : '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+   *   media_feature
+   *    : IDENT
+   */
+  List<MediaQuery> processMediaQueryList() {
+    var mediaQueries = [];
+
+    bool firstTime = true;
+    var mediaQuery;
+    do {
+      mediaQuery = processMediaQuery(firstTime == true);
+      if (mediaQuery != null) {
+        mediaQueries.add(mediaQuery);
+        firstTime = false;
+        continue;
+      }
+
+      // Any more more media types separated by comma.
+      if (!_maybeEat(TokenKind.COMMA)) break;
+
+      // Yep more media types start again.
+      firstTime = true;
+    } while ((!firstTime && mediaQuery != null) || firstTime);
+
+    return mediaQueries;
+  }
+
+  MediaQuery processMediaQuery([bool startQuery = true]) {
+    // Grammar: [ONLY | NOT]? S* media_type S*
+    //          [ AND S* MediaExpr ]* | MediaExpr [ AND S* MediaExpr ]*
+
+    int start = _peekToken.start;
+
+    // Is it a unary media operator?
+    var op = _peekToken.text;
+    var opLen = op.length;
+    var unaryOp = TokenKind.matchMediaOperator(op, 0, opLen);
+    if (unaryOp != -1) {
+      if (isChecked) {
+        if (startQuery &&
+            unaryOp != TokenKind.MEDIA_OP_NOT ||
+            unaryOp != TokenKind.MEDIA_OP_ONLY) {
+          _warning("Only the unary operators NOT and ONLY allowed",
+              _makeSpan(start));
+        }
+        if (!startQuery && unaryOp != TokenKind.MEDIA_OP_AND) {
+          _warning("Only the binary AND operator allowed", _makeSpan(start));
+        }
+      }
+      _next();
+      start = _peekToken.start;
+    }
+
+    var type;
+    if (startQuery && unaryOp != TokenKind.MEDIA_OP_AND) {
+      // Get the media type.
+      if (_peekIdentifier()) type = identifier();
+    }
+
+    var exprs = [];
+
+    if (unaryOp == -1 || unaryOp == TokenKind.MEDIA_OP_AND) {
+      var andOp = false;
+      while (true) {
+        var expr = processMediaExpression(andOp);
+        if (expr == null) break;
+
+        exprs.add(expr);
+        op = _peekToken.text;
+        opLen = op.length;
+        andOp = TokenKind.matchMediaOperator(op, 0, opLen) ==
+            TokenKind.MEDIA_OP_AND;
+        if (!andOp) break;
+        _next();
+      }
+    }
+
+    if (unaryOp != -1 || type != null || exprs.length > 0) {
+      return new MediaQuery(unaryOp, type, exprs, _makeSpan(start));
+    }
+  }
+
+  MediaExpression processMediaExpression([bool andOperator = false]) {
+    int start = _peekToken.start;
+
+    // Grammar: '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+    if (_maybeEat(TokenKind.LPAREN)) {
+      if (_peekIdentifier()) {
+        var feature = identifier();           // Media feature.
+        while (_maybeEat(TokenKind.COLON)) {
+          int startExpr = _peekToken.start;
+          var exprs = processExpr();
+          if (_maybeEat(TokenKind.RPAREN)) {
+            return new MediaExpression(andOperator, feature, exprs,
+                _makeSpan(startExpr));
+          } else if (isChecked) {
+            _warning("Missing parenthesis around media expression",
+                _makeSpan(start));
+            return null;
+          }
+        }
+      } else if (isChecked) {
+        _warning("Missing media feature in media expression", _makeSpan(start));
+        return null;
+      }
+    }
+  }
+
+  //  Directive grammar:
+  //
+  //  import:             '@import' [string | URI] media_list?
+  //  media:              '@media' media_query_list '{' ruleset '}'
+  //  page:               '@page' [':' IDENT]? '{' declarations '}'
+  //  stylet:             '@stylet' IDENT '{' ruleset '}'
+  //  media_query_list:   IDENT [',' IDENT]
+  //  keyframes:          '@-webkit-keyframes ...' (see grammar below).
+  //  font_face:          '@font-face' '{' declarations '}'
+  //  namespace:          '@namespace name url("xmlns")
+  //  host:               '@host '{' ruleset '}'
+  processDirective() {
+    int start = _peekToken.start;
+
+    var tokId = _peek();
+    // Handle case for @ directive (where there's a whitespace between the @
+    // sign and the directive name.  Technically, it's not valid grammar but
+    // a number of CSS tests test for whitespace between @ and name.
+    if (tokId == TokenKind.AT) {
+      Token tok = _next();
+      tokId = _peek();
+      if (_peekIdentifier()) {
+        // Is it a directive?
+        var directive = _peekToken.text;
+        var directiveLen = directive.length;
+        tokId = TokenKind.matchDirectives(directive, 0, directiveLen);
+        if (tokId == -1) {
+          tokId = TokenKind.matchMarginDirectives(directive, 0, directiveLen);
+        }
+      }
+
+      if (tokId == -1) {
+        if (messages.options.lessSupport) {
+          // Less compatibility:
+          //    @name: value;      =>    var-name: value;       (VarDefinition)
+          //    property: @name;   =>    property: var(name);   (VarUsage)
+          var name;
+          if (_peekIdentifier()) {
+            name = identifier();
+          }
+
+          _eat(TokenKind.COLON);
+
+          Expressions exprs = processExpr();
+
+          var span = _makeSpan(start);
+          return new VarDefinitionDirective(
+              new VarDefinition(name, exprs, span), span);
+        } else if (isChecked) {
+          _error('unexpected directive @$_peekToken', _peekToken.span);
+        }
+      }
+    }
+
+    switch (tokId) {
+      case TokenKind.DIRECTIVE_IMPORT:
+        _next();
+
+        // @import "uri_string" or @import url("uri_string") are identical; only
+        // a url can follow an @import.
+        String importStr;
+        if (_peekIdentifier()) {
+          var func = processFunction(identifier());
+          if (func is UriTerm) {
+            importStr = func.text;
+          }
+        } else {
+          importStr = processQuotedString(false);
+        }
+
+        // Any medias?
+        var medias = processMediaQueryList();
+
+        if (importStr == null) {
+          _error('missing import string', _peekToken.span);
+        }
+
+        return new ImportDirective(importStr.trim(), medias, _makeSpan(start));
+
+      case TokenKind.DIRECTIVE_MEDIA:
+        _next();
+
+        // Any medias?
+        var media = processMediaQueryList();
+
+        List<TreeNode> rulesets = [];
+        if (_maybeEat(TokenKind.LBRACE)) {
+          while (!_maybeEat(TokenKind.END_OF_FILE)) {
+            RuleSet ruleset = processRuleSet();
+            if (ruleset == null) break;
+            rulesets.add(ruleset);
+          }
+
+          if (!_maybeEat(TokenKind.RBRACE)) {
+            _error('expected } after ruleset for @media', _peekToken.span);
+          }
+        } else {
+          _error('expected { after media before ruleset', _peekToken.span);
+        }
+        return new MediaDirective(media, rulesets, _makeSpan(start));
+
+      case TokenKind.DIRECTIVE_HOST:
+        _next();
+
+        List<TreeNode> rulesets = [];
+        if (_maybeEat(TokenKind.LBRACE)) {
+          while (!_maybeEat(TokenKind.END_OF_FILE)) {
+            RuleSet ruleset = processRuleSet();
+            if (ruleset == null) break;
+            rulesets.add(ruleset);
+          }
+
+          if (!_maybeEat(TokenKind.RBRACE)) {
+            _error('expected } after ruleset for @host', _peekToken.span);
+          }
+        } else {
+          _error('expected { after host before ruleset', _peekToken.span);
+        }
+        return new HostDirective(rulesets, _makeSpan(start));
+
+      case TokenKind.DIRECTIVE_PAGE:
+        /*
+         * @page S* IDENT? pseudo_page?
+         *      S* '{' S*
+         *      [ declaration | margin ]?
+         *      [ ';' S* [ declaration | margin ]? ]* '}' S*
+         *
+         * pseudo_page :
+         *      ':' [ "left" | "right" | "first" ]
+         *
+         * margin :
+         *      margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*
+         *
+         * margin_sym : @top-left-corner, @top-left, @bottom-left, etc.
+         *
+         * See http://www.w3.org/TR/css3-page/#CSS21
+         */
+        _next();
+
+        // Page name
+        var name;
+        if (_peekIdentifier()) {
+          name = identifier();
+        }
+
+        // Any pseudo page?
+        var pseudoPage;
+        if (_maybeEat(TokenKind.COLON)) {
+          if (_peekIdentifier()) {
+            pseudoPage = identifier();
+            // TODO(terry): Normalize pseudoPage to lowercase.
+            if (isChecked &&
+                !(pseudoPage.name == 'left' ||
+                  pseudoPage.name == 'right' ||
+                  pseudoPage.name == 'first')) {
+              _warning("Pseudo page must be left, top or first",
+                  pseudoPage.span);
+              return;
+            }
+          }
+        }
+
+        String pseudoName = pseudoPage is Identifier ? pseudoPage.name : '';
+        String ident = name is Identifier ? name.name : '';
+        return new PageDirective(ident, pseudoName,
+            processMarginsDeclarations(), _makeSpan(start));
+
+      case TokenKind.DIRECTIVE_CHARSET:
+        // @charset S* STRING S* ';'
+        _next();
+
+        var charEncoding = processQuotedString(false);
+        if (isChecked && charEncoding == null) {
+          // Missing character encoding.
+          _warning('missing character encoding string', _makeSpan(start));
+        }
+
+        return new CharsetDirective(charEncoding, _makeSpan(start));
+
+      // TODO(terry): Workaround Dart2js bug continue not implemented in switch
+      //              see https://code.google.com/p/dart/issues/detail?id=8270
+      /*
+      case TokenKind.DIRECTIVE_MS_KEYFRAMES:
+        // TODO(terry): For now only IE 10 (are base level) supports @keyframes,
+        // -moz- has only been optional since Oct 2012 release of Firefox, not
+        // all versions of webkit support @keyframes and opera doesn't yet
+        // support w/o -o- prefix.  Add more warnings for other prefixes when
+        // they become optional.
+        if (isChecked) {
+          _warning('@-ms-keyframes should be @keyframes', _makeSpan(start));
+        }
+        continue keyframeDirective;
+
+      keyframeDirective:
+      */
+      case TokenKind.DIRECTIVE_KEYFRAMES:
+      case TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES:
+      case TokenKind.DIRECTIVE_MOZ_KEYFRAMES:
+      case TokenKind.DIRECTIVE_O_KEYFRAMES:
+      // TODO(terry): Remove workaround when bug 8270 is fixed.
+      case TokenKind.DIRECTIVE_MS_KEYFRAMES:
+        if (tokId == TokenKind.DIRECTIVE_MS_KEYFRAMES && isChecked) {
+          _warning('@-ms-keyframes should be @keyframes', _makeSpan(start));
+        }
+      // TODO(terry): End of workaround.
+
+        /*  Key frames grammar:
+         *
+         *  @[browser]? keyframes [IDENT|STRING] '{' keyframes-blocks '}';
+         *
+         *  browser: [-webkit-, -moz-, -ms-, -o-]
+         *
+         *  keyframes-blocks:
+         *    [keyframe-selectors '{' declarations '}']* ;
+         *
+         *  keyframe-selectors:
+         *    ['from'|'to'|PERCENTAGE] [',' ['from'|'to'|PERCENTAGE] ]* ;
+         */
+        _next();
+
+        var name;
+        if (_peekIdentifier()) {
+          name = identifier();
+        }
+
+        _eat(TokenKind.LBRACE);
+
+        var keyframe = new KeyFrameDirective(tokId, name, _makeSpan(start));
+
+        do {
+          Expressions selectors = new Expressions(_makeSpan(start));
+
+          do {
+            var term = processTerm();
+
+            // TODO(terry): Only allow from, to and PERCENTAGE ...
+
+            selectors.add(term);
+          } while (_maybeEat(TokenKind.COMMA));
+
+          keyframe.add(new KeyFrameBlock(selectors, processDeclarations(),
+              _makeSpan(start)));
+
+        } while (!_maybeEat(TokenKind.RBRACE) && !isPrematureEndOfFile());
+
+        return keyframe;
+
+      case TokenKind.DIRECTIVE_FONTFACE:
+        _next();
+        return new FontFaceDirective(processDeclarations(), _makeSpan(start));
+
+      case TokenKind.DIRECTIVE_STYLET:
+        /* Stylet grammar:
+         *
+         *  @stylet IDENT '{'
+         *    ruleset
+         *  '}'
+         */
+        _next();
+
+        var name;
+        if (_peekIdentifier()) {
+          name = identifier();
+        }
+
+        _eat(TokenKind.LBRACE);
+
+        List<TreeNode> productions = [];
+
+        start = _peekToken.start;
+        while (!_maybeEat(TokenKind.END_OF_FILE)) {
+          RuleSet ruleset = processRuleSet();
+          if (ruleset == null) {
+            break;
+          }
+          productions.add(ruleset);
+        }
+
+        _eat(TokenKind.RBRACE);
+
+        return new StyletDirective(name, productions, _makeSpan(start));
+
+      case TokenKind.DIRECTIVE_NAMESPACE:
+        /* Namespace grammar:
+         *
+         * @namespace S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
+         * namespace_prefix : IDENT
+         *
+         */
+        _next();
+
+        var prefix;
+        if (_peekIdentifier()) {
+          prefix = identifier();
+        }
+
+        // The namespace URI can be either a quoted string url("uri_string")
+        // are identical.
+        String namespaceUri;
+        if (_peekIdentifier()) {
+          var func = processFunction(identifier());
+          if (func is UriTerm) {
+            namespaceUri = func.text;
+          }
+        } else {
+          if (prefix != null && prefix.name == 'url') {
+            var func = processFunction(prefix);
+            if (func is UriTerm) {
+              // @namespace url("");
+              namespaceUri = func.text;
+              prefix = null;
+            }
+          } else {
+            namespaceUri = processQuotedString(false);
+          }
+        }
+
+        return new NamespaceDirective(prefix != null ? prefix.name : '',
+            namespaceUri, _makeSpan(start));
+    }
+  }
+
+  RuleSet processRuleSet([SelectorGroup selectorGroup]) {
+    if (selectorGroup == null) {
+      selectorGroup = processSelectorGroup();
+    }
+    if (selectorGroup != null) {
+      return new RuleSet(selectorGroup, processDeclarations(),
+          selectorGroup.span);
+    }
+  }
+
+  /**
+   * Look ahead to see if what should be a declaration is really a selector.
+   * If it's a selector than it's a nested selector.  This support's Less'
+   * nested selector syntax (requires a look ahead). E.g.,
+   *
+   *    div {
+   *      width : 20px;
+   *      span {
+   *        color: red;
+   *      }
+   *    }
+   *
+   * Two tag name selectors div and span equivalent to:
+   *
+   *    div {
+   *      width: 20px;
+   *    }
+   *    div span {
+   *      color: red;
+   *    }
+   *
+   * Return [null] if no selector or [SelectorGroup] if a selector was parsed.
+   */
+  SelectorGroup _nestedSelector() {
+    Messages oldMessages = messages;
+    _createMessages();
+
+    var markedData = _mark;
+
+    // Look a head do we have a nested selector instead of a declaration?
+    SelectorGroup selGroup = processSelectorGroup();
+
+    var nestedSelector = selGroup != null && _peekKind(TokenKind.LBRACE) &&
+        messages.messages.isEmpty;
+
+    if (!nestedSelector) {
+      // Not a selector so restore the world.
+      _restore(markedData);
+      messages = oldMessages;
+      return null;
+    } else {
+      // Remember any messages from look ahead.
+      oldMessages.mergeMessages(messages);
+      messages = oldMessages;
+      return selGroup;
+    }
+  }
+
+  processDeclarations({bool checkBrace: true}) {
+    int start = _peekToken.start;
+
+    if (checkBrace) _eat(TokenKind.LBRACE);
+
+    List decls = [];
+    List dartStyles = [];             // List of latest styles exposed to Dart.
+
+    do {
+      var selectorGroup = _nestedSelector();
+      while (selectorGroup != null) {
+        // Nested selector so process as a ruleset.
+        var ruleset = processRuleSet(selectorGroup);
+        decls.add(ruleset);
+        selectorGroup = _nestedSelector();
+      }
+
+      Declaration decl = processDeclaration(dartStyles);
+      if (decl != null) {
+        if (decl.hasDartStyle) {
+          var newDartStyle = decl.dartStyle;
+
+          // Replace or add latest Dart style.
+          bool replaced = false;
+          for (var i = 0; i < dartStyles.length; i++) {
+            var dartStyle = dartStyles[i];
+            if (dartStyle.isSame(newDartStyle)) {
+              dartStyles[i] = newDartStyle;
+              replaced = true;
+              break;
+            }
+          }
+          if (!replaced) {
+            dartStyles.add(newDartStyle);
+          }
+        }
+        decls.add(decl);
+      }
+    } while (_maybeEat(TokenKind.SEMICOLON));
+
+    if (checkBrace) _eat(TokenKind.RBRACE);
+
+    // Fixup declaration to only have dartStyle that are live for this set of
+    // declarations.
+    for (var decl in decls) {
+      if (decl is Declaration) {
+        if (decl.hasDartStyle && dartStyles.indexOf(decl.dartStyle) < 0) {
+          // Dart style not live, ignore these styles in this Declarations.
+          decl.dartStyle = null;
+        }
+      }
+    }
+
+    return new DeclarationGroup(decls, _makeSpan(start));
+  }
+
+  List<DeclarationGroup> processMarginsDeclarations() {
+    List groups = [];
+
+    int start = _peekToken.start;
+
+    _eat(TokenKind.LBRACE);
+
+    List<Declaration> decls = [];
+    List dartStyles = [];             // List of latest styles exposed to Dart.
+
+    do {
+      switch (_peek()) {
+        case TokenKind.MARGIN_DIRECTIVE_TOPLEFTCORNER:
+        case TokenKind.MARGIN_DIRECTIVE_TOPLEFT:
+        case TokenKind.MARGIN_DIRECTIVE_TOPCENTER:
+        case TokenKind.MARGIN_DIRECTIVE_TOPRIGHT:
+        case TokenKind.MARGIN_DIRECTIVE_TOPRIGHTCORNER:
+        case TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFTCORNER:
+        case TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFT:
+        case TokenKind.MARGIN_DIRECTIVE_BOTTOMCENTER:
+        case TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHT:
+        case TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHTCORNER:
+        case TokenKind.MARGIN_DIRECTIVE_LEFTTOP:
+        case TokenKind.MARGIN_DIRECTIVE_LEFTMIDDLE:
+        case TokenKind.MARGIN_DIRECTIVE_LEFTBOTTOM:
+        case TokenKind.MARGIN_DIRECTIVE_RIGHTTOP:
+        case TokenKind.MARGIN_DIRECTIVE_RIGHTMIDDLE:
+        case TokenKind.MARGIN_DIRECTIVE_RIGHTBOTTOM:
+          // Margin syms processed.
+          //   margin :
+          //      margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*
+          //
+          //      margin_sym : @top-left-corner, @top-left, @bottom-left, etc.
+          var marginSym = _peek();
+
+          _next();
+
+          var declGroup = processDeclarations();
+          if (declGroup != null) {
+            groups.add(new MarginGroup(marginSym, declGroup.declarations,
+                _makeSpan(start)));
+          }
+          break;
+        default:
+          Declaration decl = processDeclaration(dartStyles);
+          if (decl != null) {
+            if (decl.hasDartStyle) {
+              var newDartStyle = decl.dartStyle;
+
+              // Replace or add latest Dart style.
+              bool replaced = false;
+              for (var i = 0; i < dartStyles.length; i++) {
+                var dartStyle = dartStyles[i];
+                if (dartStyle.isSame(newDartStyle)) {
+                  dartStyles[i] = newDartStyle;
+                  replaced = true;
+                  break;
+                }
+              }
+              if (!replaced) {
+                dartStyles.add(newDartStyle);
+              }
+            }
+            decls.add(decl);
+          }
+          _maybeEat(TokenKind.SEMICOLON);
+          break;
+      }
+    } while (!_maybeEat(TokenKind.RBRACE) && !isPrematureEndOfFile());
+
+    // Fixup declaration to only have dartStyle that are live for this set of
+    // declarations.
+    for (var decl in decls) {
+      if (decl.hasDartStyle && dartStyles.indexOf(decl.dartStyle) < 0) {
+        // Dart style not live, ignore these styles in this Declarations.
+        decl.dartStyle = null;
+      }
+    }
+
+    if (decls.length > 0) {
+      groups.add(new DeclarationGroup(decls, _makeSpan(start)));
+    }
+
+    return groups;
+  }
+
+  SelectorGroup processSelectorGroup() {
+    List<Selector> selectors = [];
+    int start = _peekToken.start;
+    do {
+      Selector selector = processSelector();
+      if (selector != null) {
+        selectors.add(selector);
+      }
+    } while (_maybeEat(TokenKind.COMMA));
+
+    if (selectors.length > 0) {
+      return new SelectorGroup(selectors, _makeSpan(start));
+    }
+  }
+
+  /**
+   * Return list of selectors
+   */
+  processSelector() {
+    List<SimpleSelectorSequence> simpleSequences = [];
+    int start = _peekToken.start;
+    while (true) {
+      // First item is never descendant make sure it's COMBINATOR_NONE.
+      var selectorItem = simpleSelectorSequence(simpleSequences.length == 0);
+      if (selectorItem != null) {
+        simpleSequences.add(selectorItem);
+      } else {
+        break;
+      }
+    }
+
+    if (simpleSequences.length > 0) {
+      return new Selector(simpleSequences, _makeSpan(start));
+    }
+  }
+
+  simpleSelectorSequence(bool forceCombinatorNone) {
+    var start = _peekToken.start;
+    var combinatorType = TokenKind.COMBINATOR_NONE;
+    var thisOperator = false;
+
+    switch (_peek()) {
+      case TokenKind.PLUS:
+        _eat(TokenKind.PLUS);
+        combinatorType = TokenKind.COMBINATOR_PLUS;
+        break;
+      case TokenKind.GREATER:
+        _eat(TokenKind.GREATER);
+        combinatorType = TokenKind.COMBINATOR_GREATER;
+        break;
+      case TokenKind.TILDE:
+        _eat(TokenKind.TILDE);
+        combinatorType = TokenKind.COMBINATOR_TILDE;
+        break;
+      case TokenKind.AMPERSAND:
+        _eat(TokenKind.AMPERSAND);
+        thisOperator = true;
+        break;
+      }
+
+    // Check if WHITESPACE existed between tokens if so we're descendent.
+    if (combinatorType == TokenKind.COMBINATOR_NONE && !forceCombinatorNone) {
+      if (this._previousToken != null &&
+          this._previousToken.end != this._peekToken.start) {
+        combinatorType = TokenKind.COMBINATOR_DESCENDANT;
+      }
+    }
+
+    var span = _makeSpan(start);
+    var simpleSel = thisOperator ?
+        new ElementSelector(new ThisOperator(span), span) : simpleSelector();
+    if (simpleSel == null &&
+        (combinatorType == TokenKind.COMBINATOR_PLUS ||
+        combinatorType == TokenKind.COMBINATOR_GREATER ||
+        combinatorType == TokenKind.COMBINATOR_TILDE)) {
+      // For "+ &", "~ &" or "> &" a selector sequence with no name is needed
+      // so that the & will have a combinator too.  This is needed to
+      // disambiguate selector expressions:
+      //    .foo&:hover     combinator before & is NONE
+      //    .foo &          combinator before & is DESCDENDANT
+      //    .foo > &        combinator before & is GREATER
+      simpleSel =  new ElementSelector(new Identifier("", span), span);
+    }
+    if (simpleSel != null) {
+      return new SimpleSelectorSequence(simpleSel, span, combinatorType);
+    }
+  }
+
+  /**
+   * Simple selector grammar:
+   *
+   *    simple_selector_sequence
+   *       : [ type_selector | universal ]
+   *         [ HASH | class | attrib | pseudo | negation ]*
+   *       | [ HASH | class | attrib | pseudo | negation ]+
+   *    type_selector
+   *       : [ namespace_prefix ]? element_name
+   *    namespace_prefix
+   *       : [ IDENT | '*' ]? '|'
+   *    element_name
+   *       : IDENT
+   *    universal
+   *       : [ namespace_prefix ]? '*'
+   *    class
+   *       : '.' IDENT
+   */
+  simpleSelector() {
+    // TODO(terry): Nathan makes a good point parsing of namespace and element
+    //              are essentially the same (asterisk or identifier) other
+    //              than the error message for element.  Should consolidate the
+    //              code.
+    // TODO(terry): Need to handle attribute namespace too.
+    var first;
+    int start = _peekToken.start;
+    switch (_peek()) {
+      case TokenKind.ASTERISK:
+        // Mark as universal namespace.
+        var tok = _next();
+        first = new Wildcard(_makeSpan(tok.start));
+        break;
+      case TokenKind.IDENTIFIER:
+        first = identifier();
+        break;
+      default:
+        // Expecting simple selector.
+        // TODO(terry): Could be a synthesized token like value, etc.
+        if (TokenKind.isKindIdentifier(_peek())) {
+          first = identifier();
+        } else if (_peekKind(TokenKind.SEMICOLON)) {
+          // Can't be a selector if we found a semi-colon.
+          return null;
+        }
+        break;
+    }
+
+    if (_maybeEat(TokenKind.NAMESPACE)) {
+      var element;
+      switch (_peek()) {
+        case TokenKind.ASTERISK:
+          // Mark as universal element
+          var tok = _next();
+          element = new Wildcard(_makeSpan(tok.start));
+          break;
+        case TokenKind.IDENTIFIER:
+          element = identifier();
+          break;
+        default:
+          _error('expected element name or universal(*), but found $_peekToken',
+              _peekToken.span);
+          break;
+      }
+
+      return new NamespaceSelector(first,
+          new ElementSelector(element, element.span), _makeSpan(start));
+    } else if (first != null) {
+      return new ElementSelector(first, _makeSpan(start));
+    } else {
+      // Check for HASH | class | attrib | pseudo | negation
+      return simpleSelectorTail();
+    }
+  }
+
+  bool _anyWhiteSpaceBeforePeekToken(int kind) {
+    if (_previousToken != null && _peekToken != null &&
+        _previousToken.kind == kind) {
+      // If end of previous token isn't same as the start of peek token then
+      // there's something between these tokens probably whitespace.
+      return _previousToken.end != _peekToken.start;
+    }
+
+    return false;
+  }
+
+  /**
+   * type_selector | universal | HASH | class | attrib | pseudo
+   */
+  simpleSelectorTail() {
+    // Check for HASH | class | attrib | pseudo | negation
+    int start = _peekToken.start;
+    switch (_peek()) {
+      case TokenKind.HASH:
+        _eat(TokenKind.HASH);
+
+        bool hasWhiteSpace = false;
+        if (_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) {
+          _warning("Not a valid ID selector expected #id", _makeSpan(start));
+          hasWhiteSpace = true;
+        }
+        if (_peekIdentifier()) {
+          var id = identifier();
+          if (hasWhiteSpace) {
+            // Generate bad selector id (normalized).
+            id.name = " ${id.name}";
+          }
+          return new IdSelector(id, _makeSpan(start));
+        }
+        return null;
+      case TokenKind.DOT:
+        _eat(TokenKind.DOT);
+
+        bool hasWhiteSpace = false;
+        if (_anyWhiteSpaceBeforePeekToken(TokenKind.DOT)) {
+          _warning("Not a valid class selector expected .className",
+              _makeSpan(start));
+          hasWhiteSpace = true;
+        }
+        var id = identifier();
+        if (hasWhiteSpace) {
+          // Generate bad selector class (normalized).
+          id.name = " ${id.name}";
+        }
+        return new ClassSelector(id, _makeSpan(start));
+      case TokenKind.COLON:
+        // :pseudo-class ::pseudo-element
+        // TODO(terry): '::' should be token.
+        _eat(TokenKind.COLON);
+        bool pseudoElement = _maybeEat(TokenKind.COLON);
+
+        // TODO(terry): If no identifier specified consider optimizing out the
+        //              : or :: and making this a normal selector.  For now,
+        //              create an empty pseudoName.
+        var pseudoName;
+        if (_peekIdentifier()) {
+          pseudoName = identifier();
+        } else {
+          return null;
+        }
+
+        // Functional pseudo?
+        if (_maybeEat(TokenKind.LPAREN)) {
+          if (!pseudoElement && pseudoName.name.toLowerCase() == 'not') {
+            // Negation :   ':NOT(' S* negation_arg S* ')'
+            var negArg = simpleSelector();
+
+            _eat(TokenKind.RPAREN);
+            return new NegationSelector(negArg, _makeSpan(start));
+          } else {
+            // Handle function expression.
+            var span = _makeSpan(start);
+            var expr = processSelectorExpression();
+
+            // Used during selector look-a-head if not a SelectorExpression is
+            // bad.
+            if (expr is! SelectorExpression) {
+              _errorExpected("CSS expression");
+              return null;
+            }
+
+            _eat(TokenKind.RPAREN);
+            return (pseudoElement) ?
+                new PseudoElementFunctionSelector(pseudoName, expr, span) :
+                new PseudoClassFunctionSelector(pseudoName, expr, span);
+          }
+        }
+
+        // TODO(terry): Need to handle specific pseudo class/element name and
+        // backward compatible names that are : as well as :: as well as
+        // parameters.  Current, spec uses :: for pseudo-element and : for
+        // pseudo-class.  However, CSS2.1 allows for : to specify old
+        // pseudo-elements (:first-line, :first-letter, :before and :after) any
+        // new pseudo-elements defined would require a ::.
+        return pseudoElement ?
+            new PseudoElementSelector(pseudoName, _makeSpan(start)) :
+            new PseudoClassSelector(pseudoName, _makeSpan(start));
+      case TokenKind.LBRACK:
+        return processAttribute();
+      case TokenKind.DOUBLE:
+        _error('name must start with a alpha character, but found a number',
+            _peekToken.span);
+        _next();
+        break;
+    }
+  }
+
+  /**
+   *  In CSS3, the expressions are identifiers, strings, or of the form "an+b".
+   *
+   *    : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+
+   *
+   *    num               [0-9]+|[0-9]*\.[0-9]+
+   *    PLUS              '+'
+   *    DIMENSION         {num}{ident}
+   *    NUMBER            {num}
+   */
+  processSelectorExpression() {
+    int start = _peekToken.start;
+
+    var expression = new SelectorExpression(_makeSpan(start));
+
+    Token termToken;
+    var value;
+
+    // Special parsing for expressions in pseudo functions.  Minus is used as
+    // operator not identifier.
+    tokenizer.selectorExpression = true;
+
+    bool keepParsing = true;
+    while (keepParsing) {
+      switch (_peek()) {
+        case TokenKind.PLUS:
+          start = _peekToken.start;
+          termToken = _next();
+          expression.add(new OperatorPlus(_makeSpan(start)));
+          break;
+        case TokenKind.MINUS:
+          start = _peekToken.start;
+          termToken = _next();
+          expression.add(new OperatorMinus(_makeSpan(start)));
+          break;
+        case TokenKind.INTEGER:
+          termToken = _next();
+          value = int.parse(termToken.text);
+          break;
+        case TokenKind.DOUBLE:
+          termToken = _next();
+          value = double.parse(termToken.text);
+          break;
+        case TokenKind.SINGLE_QUOTE:
+        case TokenKind.DOUBLE_QUOTE:
+          value = processQuotedString(false);
+          value = '"${_escapeString(value)}"';
+          return new LiteralTerm(value, value, _makeSpan(start));
+        case TokenKind.IDENTIFIER:
+          value = identifier();   // Snarf up the ident we'll remap, maybe.
+          break;
+        default:
+          keepParsing = false;
+      }
+
+      if (keepParsing && value != null) {
+        var unitTerm;
+        // Don't process the dimension if MINUS or PLUS is next.
+        if (_peek() != TokenKind.MINUS && _peek() != TokenKind.PLUS) {
+          unitTerm = processDimension(termToken, value, _makeSpan(start));
+        }
+        if (unitTerm == null) {
+          unitTerm = new LiteralTerm(value, value.name, _makeSpan(start));
+        }
+        expression.add(unitTerm);
+
+        value = null;
+      }
+    }
+
+    tokenizer.selectorExpression = false;
+
+    return expression;
+  }
+
+  //  Attribute grammar:
+  //
+  //  attributes :
+  //    '[' S* IDENT S* [ ATTRIB_MATCHES S* [ IDENT | STRING ] S* ]? ']'
+  //
+  //  ATTRIB_MATCHES :
+  //    [ '=' | INCLUDES | DASHMATCH | PREFIXMATCH | SUFFIXMATCH | SUBSTRMATCH ]
+  //
+  //  INCLUDES:         '~='
+  //
+  //  DASHMATCH:        '|='
+  //
+  //  PREFIXMATCH:      '^='
+  //
+  //  SUFFIXMATCH:      '$='
+  //
+  //  SUBSTRMATCH:      '*='
+  //
+  //
+  processAttribute() {
+    int start = _peekToken.start;
+
+    if (_maybeEat(TokenKind.LBRACK)) {
+      var attrName = identifier();
+
+      int op;
+      switch (_peek()) {
+      case TokenKind.EQUALS:
+      case TokenKind.INCLUDES:        // ~=
+      case TokenKind.DASH_MATCH:      // |=
+      case TokenKind.PREFIX_MATCH:    // ^=
+      case TokenKind.SUFFIX_MATCH:    // $=
+      case TokenKind.SUBSTRING_MATCH: // *=
+        op = _peek();
+        _next();
+        break;
+      default:
+        op = TokenKind.NO_MATCH;
+      }
+
+      var value;
+      if (op != TokenKind.NO_MATCH) {
+        // Operator hit so we require a value too.
+        if (_peekIdentifier()) {
+          value = identifier();
+        } else {
+          value = processQuotedString(false);
+        }
+
+        if (value == null) {
+          _error('expected attribute value string or ident', _peekToken.span);
+        }
+      }
+
+      _eat(TokenKind.RBRACK);
+
+      return new AttributeSelector(attrName, op, value, _makeSpan(start));
+    }
+  }
+
+  //  Declaration grammar:
+  //
+  //  declaration:  property ':' expr prio?
+  //
+  //  property:  IDENT [or IE hacks]
+  //  prio:      !important
+  //  expr:      (see processExpr)
+  //
+  // Here are the ugly IE hacks we need to support:
+  //   property: expr prio? \9; - IE8 and below property, /9 before semi-colon
+  //   *IDENT                   - IE7 or below
+  //   _IDENT                   - IE6 property (automatically a valid ident)
+  //
+  processDeclaration(List dartStyles) {
+    Declaration decl;
+
+    int start = _peekToken.start;
+
+    // IE7 hack of * before property name if so the property is IE7 or below.
+    var ie7 = _peekKind(TokenKind.ASTERISK);
+    if (ie7) {
+      _next();
+    }
+
+    // IDENT ':' expr '!important'?
+    if (TokenKind.isIdentifier(_peekToken.kind)) {
+      var propertyIdent = identifier();
+
+      var ieFilterProperty = propertyIdent.name.toLowerCase() == 'filter';
+
+      _eat(TokenKind.COLON);
+
+      Expressions exprs = processExpr(ieFilterProperty);
+
+      var dartComposite = _styleForDart(propertyIdent, exprs, dartStyles);
+
+      // Handle !important (prio)
+      var importantPriority = _maybeEat(TokenKind.IMPORTANT);
+
+      decl = new Declaration(propertyIdent, exprs, dartComposite,
+          _makeSpan(start), important: importantPriority, ie7: ie7);
+    } else if (_peekToken.kind == TokenKind.VAR_DEFINITION) {
+      _next();
+      var definedName;
+      if (_peekIdentifier()) definedName = identifier();
+
+      _eat(TokenKind.COLON);
+
+      Expressions exprs = processExpr();
+
+      decl = new VarDefinition(definedName, exprs, _makeSpan(start));
+    }
+
+    return decl;
+  }
+
+  /** List of styles exposed to the Dart UI framework. */
+  static const int _fontPartFont= 0;
+  static const int _fontPartVariant = 1;
+  static const int _fontPartWeight = 2;
+  static const int _fontPartSize = 3;
+  static const int _fontPartFamily = 4;
+  static const int _fontPartStyle = 5;
+  static const int _marginPartMargin = 6;
+  static const int _marginPartLeft = 7;
+  static const int _marginPartTop = 8;
+  static const int _marginPartRight = 9;
+  static const int _marginPartBottom = 10;
+  static const int _lineHeightPart = 11;
+  static const int _borderPartBorder = 12;
+  static const int _borderPartLeft = 13;
+  static const int _borderPartTop = 14;
+  static const int _borderPartRight = 15;
+  static const int _borderPartBottom = 16;
+  static const int _borderPartWidth = 17;
+  static const int _borderPartLeftWidth = 18;
+  static const int _borderPartTopWidth = 19;
+  static const int _borderPartRightWidth = 20;
+  static const int _borderPartBottomWidth = 21;
+  static const int _heightPart = 22;
+  static const int _widthPart = 23;
+  static const int _paddingPartPadding = 24;
+  static const int _paddingPartLeft = 25;
+  static const int _paddingPartTop = 26;
+  static const int _paddingPartRight = 27;
+  static const int _paddingPartBottom = 28;
+
+  static const Map<String, int> _stylesToDart = const {
+    'font':                 _fontPartFont,
+    'font-family':          _fontPartFamily,
+    'font-size':            _fontPartSize,
+    'font-style':           _fontPartStyle,
+    'font-variant':         _fontPartVariant,
+    'font-weight':          _fontPartWeight,
+    'line-height':          _lineHeightPart,
+    'margin':               _marginPartMargin,
+    'margin-left':          _marginPartLeft,
+    'margin-right':         _marginPartRight,
+    'margin-top':           _marginPartTop,
+    'margin-bottom':        _marginPartBottom,
+    'border':               _borderPartBorder,
+    'border-left':          _borderPartLeft,
+    'border-right':         _borderPartRight,
+    'border-top':           _borderPartTop,
+    'border-bottom':        _borderPartBottom,
+    'border-width':         _borderPartWidth,
+    'border-left-width':    _borderPartLeftWidth,
+    'border-top-width':     _borderPartTopWidth,
+    'border-right-width':   _borderPartRightWidth,
+    'border-bottom-width':  _borderPartBottomWidth,
+    'height':               _heightPart,
+    'width':                _widthPart,
+    'padding':              _paddingPartPadding,
+    'padding-left':         _paddingPartLeft,
+    'padding-top':          _paddingPartTop,
+    'padding-right':        _paddingPartRight,
+    'padding-bottom':       _paddingPartBottom
+  };
+
+  static const Map<String, int> _nameToFontWeight = const {
+    'bold' : FontWeight.bold,
+    'normal' : FontWeight.normal
+  };
+
+  static _findStyle(String styleName) {
+    if (_stylesToDart.containsKey(styleName)) {
+      return _stylesToDart[styleName];
+    }
+  }
+
+  _styleForDart(Identifier property, Expressions exprs, List dartStyles) {
+    int styleType = _findStyle(property.name.toLowerCase());
+    if (styleType != null) {
+      return buildDartStyleNode(styleType, exprs, dartStyles);
+    }
+  }
+
+  FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) {
+    // Merge all font styles for this class selector.
+    for (var dartStyle in dartStyles) {
+      if (dartStyle.isFont) {
+        fontExpr = new FontExpression.merge(dartStyle, fontExpr);
+      }
+    }
+
+    return fontExpr;
+  }
+
+  buildDartStyleNode(int styleType, Expressions exprs, List dartStyles) {
+    switch (styleType) {
+      /*
+       * Properties in order:
+       *
+       *   font-style font-variant font-weight font-size/line-height font-family
+       *
+       * The font-size and font-family values are required. If other values are
+       * missing; a default, if it exist, will be used.
+       */
+       case _fontPartFont:
+         var processor = new ExpressionsProcessor(exprs);
+         return _mergeFontStyles(processor.processFont(), dartStyles);
+      case _fontPartFamily:
+        var processor = new ExpressionsProcessor(exprs);
+
+        try {
+          return _mergeFontStyles(processor.processFontFamily(), dartStyles);
+        } catch (fontException) {
+          _error(fontException, _peekToken.span);
+        }
+        break;
+      case _fontPartSize:
+        var processor = new ExpressionsProcessor(exprs);
+        return _mergeFontStyles(processor.processFontSize(), dartStyles);
+      case _fontPartStyle:
+        /* Possible style values:
+         *   normal [default]
+         *   italic
+         *   oblique
+         *   inherit
+         */
+        // TODO(terry): TBD
+        break;
+      case _fontPartVariant:
+        /* Possible variant values:
+         *   normal  [default]
+         *   small-caps
+         *   inherit
+         */
+        // TODO(terry): TBD
+        break;
+      case _fontPartWeight:
+        /* Possible weight values:
+         *   normal [default]
+         *   bold
+         *   bolder
+         *   lighter
+         *   100 - 900
+         *   inherit
+         */
+        // TODO(terry): Only 'normal', 'bold', or values of 100-900 supoorted
+        //              need to handle bolder, lighter, and inherit.  See
+        //              https://github.com/dart-lang/csslib/issues/1
+        var expr = exprs.expressions[0];
+        if (expr is NumberTerm) {
+          var fontExpr = new FontExpression(expr.span,
+              weight: expr.value);
+          return _mergeFontStyles(fontExpr, dartStyles);
+        } else if (expr is LiteralTerm) {
+          int weight = _nameToFontWeight[expr.value.toString()];
+          if (weight != null) {
+            var fontExpr = new FontExpression(expr.span, weight: weight);
+            return _mergeFontStyles(fontExpr, dartStyles);
+          }
+        }
+        break;
+      case _lineHeightPart:
+        num lineHeight;
+        if (exprs.expressions.length == 1) {
+          var expr = exprs.expressions[0];
+          if (expr is UnitTerm) {
+            UnitTerm unitTerm = expr;
+            // TODO(terry): Need to handle other units and LiteralTerm normal
+            //              See https://github.com/dart-lang/csslib/issues/2.
+            if (unitTerm.unit == TokenKind.UNIT_LENGTH_PX ||
+                   unitTerm.unit == TokenKind.UNIT_LENGTH_PT) {
+              var fontExpr = new FontExpression(expr.span,
+                  lineHeight: new LineHeight(expr.value, inPixels: true));
+              return _mergeFontStyles(fontExpr, dartStyles);
+            } else if (isChecked) {
+              _warning("Unexpected unit for line-height", expr.span);
+            }
+          } else if (expr is NumberTerm) {
+            var fontExpr = new FontExpression(expr.span,
+                lineHeight: new LineHeight(expr.value, inPixels: false));
+            return _mergeFontStyles(fontExpr, dartStyles);
+          } else if (isChecked) {
+            _warning("Unexpected value for line-height", expr.span);
+          }
+        }
+        break;
+      case _marginPartMargin:
+        return new MarginExpression.boxEdge(exprs.span, processFourNums(exprs));
+      case _borderPartBorder:
+        for (var expr in exprs.expressions) {
+          var v = marginValue(expr);
+          if (v != null) {
+            final box = new BoxEdge.uniform(v);
+            return new BorderExpression.boxEdge(exprs.span, box);
+          }
+        }
+        break;
+      case _borderPartWidth:
+        var v = marginValue(exprs.expressions[0]);
+        if (v != null) {
+          final box = new BoxEdge.uniform(v);
+          return new BorderExpression.boxEdge(exprs.span, box);
+        }
+        break;
+      case _paddingPartPadding:
+        return new PaddingExpression.boxEdge(exprs.span,
+            processFourNums(exprs));
+      case _marginPartLeft:
+      case _marginPartTop:
+      case _marginPartRight:
+      case _marginPartBottom:
+      case _borderPartLeft:
+      case _borderPartTop:
+      case _borderPartRight:
+      case _borderPartBottom:
+      case _borderPartLeftWidth:
+      case _borderPartTopWidth:
+      case _borderPartRightWidth:
+      case _borderPartBottomWidth:
+      case _heightPart:
+      case _widthPart:
+      case _paddingPartLeft:
+      case _paddingPartTop:
+      case _paddingPartRight:
+      case _paddingPartBottom:
+        if (exprs.expressions.length > 0) {
+          return processOneNumber(exprs, styleType);
+        }
+        break;
+      default:
+        // Don't handle it.
+        return;
+    }
+  }
+
+  // TODO(terry): Look at handling width of thin, thick, etc. any none numbers
+  //              to convert to a number.
+  processOneNumber(Expressions exprs, int part) {
+    var value = marginValue(exprs.expressions[0]);
+    if (value != null) {
+      switch (part) {
+        case _marginPartLeft:
+          return new MarginExpression(exprs.span, left: value);
+        case _marginPartTop:
+          return new MarginExpression(exprs.span, top: value);
+        case _marginPartRight:
+          return new MarginExpression(exprs.span, right: value);
+        case _marginPartBottom:
+          return new MarginExpression(exprs.span, bottom: value);
+        case _borderPartLeft:
+        case _borderPartLeftWidth:
+          return new BorderExpression(exprs.span, left: value);
+        case _borderPartTop:
+        case _borderPartTopWidth:
+          return new BorderExpression(exprs.span, top: value);
+        case _borderPartRight:
+        case _borderPartRightWidth:
+          return new BorderExpression(exprs.span, right: value);
+        case _borderPartBottom:
+        case _borderPartBottomWidth:
+          return new BorderExpression(exprs.span, bottom: value);
+        case _heightPart:
+          return new HeightExpression(exprs.span, value);
+        case _widthPart:
+          return new WidthExpression(exprs.span, value);
+        case _paddingPartLeft:
+          return new PaddingExpression(exprs.span, left: value);
+        case _paddingPartTop:
+          return new PaddingExpression(exprs.span, top: value);
+        case _paddingPartRight:
+          return new PaddingExpression(exprs.span, right: value);
+        case _paddingPartBottom:
+          return new PaddingExpression(exprs.span, bottom: value);
+      }
+    }
+  }
+
+  /**
+   * Margins are of the format:
+   *
+   *   top,right,bottom,left      (4 parameters)
+   *   top,right/left, bottom     (3 parameters)
+   *   top/bottom,right/left      (2 parameters)
+   *   top/right/bottom/left      (1 parameter)
+   *
+   * The values of the margins can be a unit or unitless or auto.
+   */
+  processFourNums(Expressions exprs) {
+    num top;
+    num right;
+    num bottom;
+    num left;
+
+    int totalExprs = exprs.expressions.length;
+    switch (totalExprs) {
+      case 1:
+        top = marginValue(exprs.expressions[0]);
+        right = top;
+        bottom = top;
+        left = top;
+        break;
+      case 2:
+        top = marginValue(exprs.expressions[0]);
+        bottom = top;
+        right = marginValue(exprs.expressions[1]);
+        left = right;
+       break;
+      case 3:
+        top = marginValue(exprs.expressions[0]);
+        right = marginValue(exprs.expressions[1]);
+        left = right;
+        bottom = marginValue(exprs.expressions[2]);
+        break;
+      case 4:
+        top = marginValue(exprs.expressions[0]);
+        right = marginValue(exprs.expressions[1]);
+        bottom = marginValue(exprs.expressions[2]);
+        left = marginValue(exprs.expressions[3]);
+        break;
+      default:
+        return;
+    }
+
+    return new BoxEdge.clockwiseFromTop(top, right, bottom, left);
+  }
+
+  // TODO(terry): Need to handle auto.
+  marginValue(var exprTerm) {
+    if (exprTerm is UnitTerm || exprTerm is NumberTerm) {
+      return exprTerm.value;
+    }
+  }
+
+  //  Expression grammar:
+  //
+  //  expression:   term [ operator? term]*
+  //
+  //  operator:     '/' | ','
+  //  term:         (see processTerm)
+  //
+  processExpr([bool ieFilter = false]) {
+    int start = _peekToken.start;
+    Expressions expressions = new Expressions(_makeSpan(start));
+
+    bool keepGoing = true;
+    var expr;
+    while (keepGoing && (expr = processTerm(ieFilter)) != null) {
+      var op;
+
+      int opStart = _peekToken.start;
+
+      switch (_peek()) {
+      case TokenKind.SLASH:
+        op = new OperatorSlash(_makeSpan(opStart));
+        break;
+      case TokenKind.COMMA:
+        op = new OperatorComma(_makeSpan(opStart));
+        break;
+      case TokenKind.BACKSLASH:
+        // Backslash outside of string; detected IE8 or older signaled by \9 at
+        // end of an expression.
+        var ie8Start = _peekToken.start;
+
+        _next();
+        if (_peekKind(TokenKind.INTEGER)) {
+          var numToken = _next();
+          var value = int.parse(numToken.text);
+          if (value == 9) {
+            op = new IE8Term(_makeSpan(ie8Start));
+          } else if (isChecked) {
+            _warning("\$value is not valid in an expression", _makeSpan(start));
+          }
+        }
+        break;
+      }
+
+      if (expr != null) {
+        expressions.add(expr);
+      } else {
+        keepGoing = false;
+      }
+
+      if (op != null) {
+        expressions.add(op);
+        if (op is IE8Term) {
+          keepGoing = false;
+        } else {
+          _next();
+        }
+      }
+    }
+
+    return expressions;
+  }
+
+  static int MAX_UNICODE = int.parse('0x10FFFF');
+
+  //  Term grammar:
+  //
+  //  term:
+  //    unary_operator?
+  //    [ term_value ]
+  //    | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor
+  //
+  //  term_value:
+  //    NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
+  //    TIME S* | FREQ S* | function
+  //
+  //  NUMBER:       {num}
+  //  PERCENTAGE:   {num}%
+  //  LENGTH:       {num}['px' | 'cm' | 'mm' | 'in' | 'pt' | 'pc']
+  //  EMS:          {num}'em'
+  //  EXS:          {num}'ex'
+  //  ANGLE:        {num}['deg' | 'rad' | 'grad']
+  //  TIME:         {num}['ms' | 's']
+  //  FREQ:         {num}['hz' | 'khz']
+  //  function:     IDENT '(' expr ')'
+  //
+  processTerm([bool ieFilter = false]) {
+    int start = _peekToken.start;
+    Token t;                          // token for term's value
+    var value;                        // value of term (numeric values)
+
+    var unary = "";
+    switch (_peek()) {
+    case TokenKind.HASH:
+      this._eat(TokenKind.HASH);
+      if (!_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) {
+        String hexText;
+        if (_peekKind(TokenKind.INTEGER)) {
+          String hexText1 = _peekToken.text;
+          _next();
+          if (_peekIdentifier()) {
+            hexText = '$hexText1${identifier().name}';
+          } else {
+            hexText = hexText1;
+          }
+        } else if (_peekIdentifier()) {
+          hexText = identifier().name;
+        }
+        if (hexText != null) {
+          return _parseHex(hexText, _makeSpan(start));
+        }
+      }
+
+      if (isChecked) {
+        _warning("Expected hex number", _makeSpan(start));
+      }
+      // Construct the bad hex value with a #<space>number.
+      return _parseHex(" ${processTerm().text}", _makeSpan(start));
+    case TokenKind.INTEGER:
+      t = _next();
+      value = int.parse("${unary}${t.text}");
+      break;
+    case TokenKind.DOUBLE:
+      t = _next();
+      value = double.parse("${unary}${t.text}");
+      break;
+    case TokenKind.SINGLE_QUOTE:
+    case TokenKind.DOUBLE_QUOTE:
+      value = processQuotedString(false);
+      value = '"${_escapeString(value)}"';
+      return new LiteralTerm(value, value, _makeSpan(start));
+    case TokenKind.LPAREN:
+      _next();
+
+      GroupTerm group = new GroupTerm(_makeSpan(start));
+
+      var term;
+      do {
+        term = processTerm();
+        if (term != null && term is LiteralTerm) {
+          group.add(term);
+        }
+      } while (term != null && !_maybeEat(TokenKind.RPAREN) &&
+          !isPrematureEndOfFile());
+
+      return group;
+    case TokenKind.LBRACK:
+      _next();
+
+      var term = processTerm();
+      if (!(term is NumberTerm)) {
+        _error('Expecting a positive number', _makeSpan(start));
+      }
+
+      _eat(TokenKind.RBRACK);
+
+      return new ItemTerm(term.value, term.text, _makeSpan(start));
+    case TokenKind.IDENTIFIER:
+      var nameValue = identifier();   // Snarf up the ident we'll remap, maybe.
+
+      if (!ieFilter && _maybeEat(TokenKind.LPAREN)) {
+        // FUNCTION
+        return processFunction(nameValue);
+      } if (ieFilter) {
+         if (_maybeEat(TokenKind.COLON) &&
+           nameValue.name.toLowerCase() == 'progid') {
+           // IE filter:progid:
+           return processIEFilter(start);
+         } else {
+           // Handle filter:<name> where name is any filter e.g., alpha, chroma,
+           // Wave, blur, etc.
+           return processIEFilter(start);
+         }
+      }
+
+      // TODO(terry): Need to have a list of known identifiers today only
+      //              'from' is special.
+      if (nameValue.name == 'from') {
+        return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start));
+      }
+
+      // What kind of identifier is it, named color?
+      var colorEntry = TokenKind.matchColorName(nameValue.name);
+      if (colorEntry == null) {
+        if (isChecked) {
+          var propName = nameValue.name;
+          var errMsg = TokenKind.isPredefinedName(propName) ?
+              "Improper use of property value ${propName}" :
+              "Unknown property value ${propName}";
+          _warning(errMsg, _makeSpan(start));
+        }
+        return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start));
+      }
+
+      // Yes, process the color as an RGB value.
+      String rgbColor = TokenKind.decimalToHex(
+          TokenKind.colorValue(colorEntry), 6);
+      return _parseHex(rgbColor, _makeSpan(start));
+    case TokenKind.UNICODE_RANGE:
+      var first;
+      var second;
+      var firstNumber;
+      var secondNumber;
+      _eat(TokenKind.UNICODE_RANGE, unicodeRange: true);
+      if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) {
+        first = _previousToken.text;
+        firstNumber = int.parse('0x$first');
+        if (firstNumber > MAX_UNICODE) {
+          _error("unicode range must be less than 10FFFF", _makeSpan(start));
+        }
+        if (_maybeEat(TokenKind.MINUS, unicodeRange: true)) {
+          if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) {
+            second = _previousToken.text;
+            secondNumber = int.parse('0x$second');
+            if (secondNumber > MAX_UNICODE) {
+              _error("unicode range must be less than 10FFFF",
+                  _makeSpan(start));
+            }
+            if (firstNumber > secondNumber) {
+              _error("unicode first range can not be greater than last",
+                  _makeSpan(start));
+            }
+          }
+        }
+      } else if (_maybeEat(TokenKind.HEX_RANGE, unicodeRange: true)) {
+        first = _previousToken.text;
+      }
+
+      return new UnicodeRangeTerm(first, second, _makeSpan(start));
+    case TokenKind.AT:
+      if (messages.options.lessSupport) {
+        _next();
+
+        var expr = processExpr();
+        if (isChecked && expr.expressions.length > 1) {
+          _error("only @name for Less syntax", _peekToken.span);
+        }
+
+        var param = expr.expressions[0];
+        return new VarUsage(param.text, [], _makeSpan(start));
+      }
+      break;
+    }
+
+    return processDimension(t, value, _makeSpan(start));
+  }
+
+  /** Process all dimension units. */
+  processDimension(Token t, var value, Span span) {
+    var term;
+    var unitType = this._peek();
+
+    switch (unitType) {
+    case TokenKind.UNIT_EM:
+      term = new EmTerm(value, t.text, span);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_EX:
+      term = new ExTerm(value, t.text, span);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_LENGTH_PX:
+    case TokenKind.UNIT_LENGTH_CM:
+    case TokenKind.UNIT_LENGTH_MM:
+    case TokenKind.UNIT_LENGTH_IN:
+    case TokenKind.UNIT_LENGTH_PT:
+    case TokenKind.UNIT_LENGTH_PC:
+      term = new LengthTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_ANGLE_DEG:
+    case TokenKind.UNIT_ANGLE_RAD:
+    case TokenKind.UNIT_ANGLE_GRAD:
+    case TokenKind.UNIT_ANGLE_TURN:
+      term = new AngleTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_TIME_MS:
+    case TokenKind.UNIT_TIME_S:
+      term = new TimeTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_FREQ_HZ:
+    case TokenKind.UNIT_FREQ_KHZ:
+      term = new FreqTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.PERCENT:
+      term = new PercentageTerm(value, t.text, span);
+      _next();    // Skip the %
+      break;
+    case TokenKind.UNIT_FRACTION:
+      term = new FractionTerm(value, t.text, span);
+      _next();     // Skip the unit
+      break;
+    case TokenKind.UNIT_RESOLUTION_DPI:
+    case TokenKind.UNIT_RESOLUTION_DPCM:
+    case TokenKind.UNIT_RESOLUTION_DPPX:
+      term = new ResolutionTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_CH:
+      term = new ChTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_REM:
+      term = new RemTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    case TokenKind.UNIT_VIEWPORT_VW:
+    case TokenKind.UNIT_VIEWPORT_VH:
+    case TokenKind.UNIT_VIEWPORT_VMIN:
+    case TokenKind.UNIT_VIEWPORT_VMAX:
+      term = new ViewportTerm(value, t.text, span, unitType);
+      _next();    // Skip the unit
+      break;
+    default:
+      if (value != null && t != null) {
+        term = (value is Identifier)
+            ? new LiteralTerm(value, value.name, span)
+            : new NumberTerm(value, t.text, span);
+      }
+      break;
+    }
+
+    return term;
+  }
+
+  processQuotedString([bool urlString = false]) {
+    int start = _peekToken.start;
+
+    // URI term sucks up everything inside of quotes(' or ") or between parens
+    int stopToken = urlString ? TokenKind.RPAREN : -1;
+    switch (_peek()) {
+    case TokenKind.SINGLE_QUOTE:
+      stopToken = TokenKind.SINGLE_QUOTE;
+      start = _peekToken.start + 1;   // Skip the quote might have whitespace.
+      _next();    // Skip the SINGLE_QUOTE.
+      break;
+    case TokenKind.DOUBLE_QUOTE:
+      stopToken = TokenKind.DOUBLE_QUOTE;
+      start = _peekToken.start + 1;   // Skip the quote might have whitespace.
+      _next();    // Skip the DOUBLE_QUOTE.
+      break;
+    default:
+      if (urlString) {
+        if (_peek() == TokenKind.LPAREN) {
+          _next();    // Skip the LPAREN.
+          start = _peekToken.start;
+        }
+        stopToken = TokenKind.RPAREN;
+      } else {
+        _error('unexpected string', _makeSpan(start));
+      }
+      break;
+    }
+
+    // Gobble up everything until we hit our stop token.
+    int runningStart = _peekToken.start;
+    while (_peek() != stopToken && _peek() != TokenKind.END_OF_FILE) {
+      var tok = _next();
+    }
+
+    // All characters between quotes is the string.
+    int end = _peekToken.end;
+    var stringValue = (_peekToken.span as FileSpan).file.getText(start,
+        end - 1);
+
+    if (stopToken != TokenKind.RPAREN) {
+      _next();    // Skip the SINGLE_QUOTE or DOUBLE_QUOTE;
+    }
+
+    return stringValue;
+  }
+
+  // TODO(terry): Should probably understand IE's non-standard filter syntax to
+  //              fully support calc, var(), etc.
+  /**
+   * IE's filter property breaks CSS value parsing.  IE's format can be:
+   *
+   *    filter: progid:DXImageTransform.MS.gradient(Type=0, Color='#9d8b83');
+   *
+   * We'll just parse everything after the 'progid:' look for the left paren
+   * then parse to the right paren ignoring everything in between.
+   */
+  processIEFilter(int startAfterProgidColon) {
+    int parens = 0;
+
+    while (_peek() != TokenKind.END_OF_FILE) {
+      switch (_peek()) {
+        case TokenKind.LPAREN:
+          _eat(TokenKind.LPAREN);
+          parens++;
+          break;
+        case TokenKind.RPAREN:
+          _eat(TokenKind.RPAREN);
+          if (--parens == 0) {
+            var tok = tokenizer.makeIEFilter(startAfterProgidColon,
+                _peekToken.start);
+            return new LiteralTerm(tok.text, tok.text, tok.span);
+          }
+          break;
+        default:
+          _eat(_peek());
+      }
+    }
+  }
+
+  //  Function grammar:
+  //
+  //  function:     IDENT '(' expr ')'
+  //
+  processFunction(Identifier func) {
+    int start = _peekToken.start;
+
+    String name = func.name;
+
+    switch (name) {
+    case 'url':
+      // URI term sucks up everything inside of quotes(' or ") or between parens
+      String urlParam = processQuotedString(true);
+
+      // TODO(terry): Better error messge and checking for mismatched quotes.
+      if (_peek() == TokenKind.END_OF_FILE) {
+        _error("problem parsing URI", _peekToken.span);
+      }
+
+      if (_peek() == TokenKind.RPAREN) {
+        _next();
+      }
+
+      return new UriTerm(urlParam, _makeSpan(start));
+    case 'calc':
+      // TODO(terry): Implement expression handling...
+      break;
+    case 'var':
+      // TODO(terry): Consider handling var in IE specific filter/progid.  This
+      //              will require parsing entire IE specific syntax e.g.,
+      //              param = value or progid:com_id, etc. for example:
+      //
+      //    var-blur: Blur(Add = 0, Direction = 225, Strength = 10);
+      //    var-gradient: progid:DXImageTransform.Microsoft.gradient"
+      //      (GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
+      var expr = processExpr();
+      if (!_maybeEat(TokenKind.RPAREN)) {
+        _error("problem parsing var expected ), ", _peekToken.span);
+      }
+      if (isChecked &&
+          expr.expressions.where((e) => e is OperatorComma).length > 1) {
+        _error("too many parameters to var()", _peekToken.span);
+      }
+
+      var paramName = expr.expressions[0].text;
+
+      // [0] - var name, [1] - OperatorComma, [2] - default value.
+      var defaultValues = expr.expressions.length >= 3
+          ? expr.expressions.sublist(2) : [];
+      return new VarUsage(paramName, defaultValues, _makeSpan(start));
+    default:
+      var expr = processExpr();
+      if (!_maybeEat(TokenKind.RPAREN)) {
+        _error("problem parsing function expected ), ", _peekToken.span);
+      }
+
+      return new FunctionTerm(name, name, expr, _makeSpan(start));
+    }
+
+    return null;
+  }
+
+  identifier() {
+    var tok = _next();
+
+    if (!TokenKind.isIdentifier(tok.kind) &&
+        !TokenKind.isKindIdentifier(tok.kind)) {
+      if (isChecked) {
+        _warning('expected identifier, but found $tok', tok.span);
+      }
+      return new Identifier("", _makeSpan(tok.start));
+    }
+
+    return new Identifier(tok.text, _makeSpan(tok.start));
+  }
+
+  // TODO(terry): Move this to base <= 36 and into shared code.
+  static int _hexDigit(int c) {
+    if(c >= 48/*0*/ && c <= 57/*9*/) {
+      return c - 48;
+    } else if (c >= 97/*a*/ && c <= 102/*f*/) {
+      return c - 87;
+    } else if (c >= 65/*A*/ && c <= 70/*F*/) {
+      return c - 55;
+    } else {
+      return -1;
+    }
+  }
+
+  HexColorTerm _parseHex(String hexText, Span span) {
+    int hexValue = 0;
+
+     for (int i = 0; i < hexText.length; i++) {
+      var digit = _hexDigit(hexText.codeUnitAt(i));
+      if (digit < 0) {
+        _warning('Bad hex number', span);
+        return new HexColorTerm(new BAD_HEX_VALUE(), hexText, span);
+      }
+      hexValue = (hexValue << 4) + digit;
+    }
+
+    // Make 3 character hex value #RRGGBB => #RGB iff:
+    // high/low nibble of RR is the same, high/low nibble of GG is the same and
+    // high/low nibble of BB is the same.
+    if (hexText.length == 6 &&
+        hexText[0] == hexText[1] &&
+        hexText[2] == hexText[3] &&
+        hexText[4] == hexText[5]) {
+      hexText = '${hexText[0]}${hexText[2]}${hexText[4]}';
+    } else if (hexText.length == 4 &&
+        hexText[0] == hexText[1] &&
+        hexText[2] == hexText[3]) {
+      hexText = '${hexText[0]}${hexText[2]}';
+    } else if (hexText.length == 2 && hexText[0] == hexText[1]) {
+      hexText = '${hexText[0]}';
+    }
+    return new HexColorTerm(hexValue, hexText, span);
+  }
+}
+
+class ExpressionsProcessor {
+  final Expressions _exprs;
+  int _index = 0;
+
+  ExpressionsProcessor(this._exprs);
+
+  // TODO(terry): Only handles ##px unit.
+  processFontSize() {
+    /* font-size[/line-height]
+     *
+     * Possible size values:
+     *   xx-small
+     *   small
+     *   medium [default]
+     *   large
+     *   x-large
+     *   xx-large
+     *   smaller
+     *   larger
+     *   ##length in px, pt, etc.
+     *   ##%, percent of parent elem's font-size
+     *   inherit
+     */
+    LengthTerm size;
+    LineHeight lineHt;
+    bool nextIsLineHeight = false;
+    for (; _index < _exprs.expressions.length; _index++) {
+      var expr = _exprs.expressions[_index];
+      if (size == null && expr is LengthTerm) {
+        // font-size part.
+        size = expr;
+      } else if (size != null) {
+        if (expr is OperatorSlash) {
+          // LineHeight could follow?
+          nextIsLineHeight = true;
+        } else if (nextIsLineHeight && expr is LengthTerm) {
+          assert(expr.unit == TokenKind.UNIT_LENGTH_PX);
+          lineHt = new LineHeight(expr.value, inPixels: true);
+          nextIsLineHeight = false;
+          _index++;
+          break;
+        } else {
+          break;
+        }
+      } else {
+        break;
+      }
+    }
+
+    return new FontExpression(_exprs.span, size: size, lineHeight: lineHt);
+  }
+
+  processFontFamily() {
+    final List<String> family = <String>[];
+
+    /* Possible family values:
+     * font-family: arial, Times new roman ,Lucida Sans Unicode,Courier;
+     * font-family: "Times New Roman", arial, Lucida Sans Unicode, Courier;
+     */
+    bool moreFamilies = false;
+
+    for (; _index < _exprs.expressions.length; _index++) {
+      Expression expr = _exprs.expressions[_index];
+      if (expr is LiteralTerm) {
+        if (family.length == 0 || moreFamilies) {
+          // It's font-family now.
+          family.add(expr.toString());
+          moreFamilies = false;
+        } else if (isChecked) {
+          messages.warning('Only font-family can be a list', _exprs.span);
+        }
+      } else if (expr is OperatorComma && family.length > 0) {
+        moreFamilies = true;
+      } else {
+        break;
+      }
+    }
+
+    return new FontExpression(_exprs.span, family: family);
+  }
+
+  processFont() {
+    var family;
+
+    // Process all parts of the font expression.
+    FontExpression fontSize;
+    FontExpression fontFamily;
+    for (; _index < _exprs.expressions.length; _index++) {
+      var expr = _exprs.expressions[_index];
+      // Order is font-size font-family
+      if (fontSize == null) {
+        fontSize = processFontSize();
+      }
+      if (fontFamily == null) {
+        fontFamily = processFontFamily();
+      }
+      //TODO(terry): Handle font-weight, font-style, and font-variant. See
+      //               https://github.com/dart-lang/csslib/issues/3
+      //               https://github.com/dart-lang/csslib/issues/4
+      //               https://github.com/dart-lang/csslib/issues/5
+    }
+
+    return new FontExpression(_exprs.span,
+        size: fontSize.font.size,
+        lineHeight: fontSize.font.lineHeight,
+        family: fontFamily.font.family);
+  }
+}
+
+/**
+ * Escapes [text] for use in a CSS string.
+ * [single] specifies single quote `'` vs double quote `"`.
+ */
+String _escapeString(String text, {bool single: false}) {
+  StringBuffer result = null;
+
+  for (int i = 0; i < text.length; i++) {
+    int code = text.codeUnitAt(i);
+    var replace = null;
+    switch (code) {
+      case 34/*'"'*/:  if (!single) replace = r'\"'; break;
+      case 39/*"'"*/:  if (single) replace = r"\'"; break;
+    }
+
+    if (replace != null && result == null) {
+      result = new StringBuffer(text.substring(0, i));
+    }
+
+    if (result != null) result.write(replace != null ? replace : text[i]);
+  }
+
+  return result == null ? text : result.toString();
+}
diff --git a/pkg/csslib/lib/src/analyzer.dart b/pkg/csslib/lib/src/analyzer.dart
new file mode 100644
index 0000000..9e366a5
--- /dev/null
+++ b/pkg/csslib/lib/src/analyzer.dart
@@ -0,0 +1,513 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.parser;
+
+
+// TODO(terry): Detect invalid directive usage.  All @imports must occur before
+//              all rules other than @charset directive.  Any @import directive
+//              after any non @charset or @import directive are ignored. e.g.,
+//                  @import "a.css";
+//                  div { color: red; }
+//                  @import "b.css";
+//              becomes:
+//                  @import "a.css";
+//                  div { color: red; }
+// <http://www.w3.org/TR/css3-syntax/#at-rules>
+
+/**
+ * Analysis phase will validate/fixup any new CSS feature or any SASS style
+ * feature.
+ */
+class Analyzer {
+  final List<StyleSheet> _styleSheets;
+  final Messages _messages;
+  VarDefinitions varDefs;
+
+  Analyzer(this._styleSheets, this._messages);
+
+  void run() {
+    varDefs = new VarDefinitions(_styleSheets);
+
+    // Any cycles?
+    var cycles = findAllCycles();
+    for (var cycle in cycles) {
+      _messages.warning("var cycle detected var-${cycle.definedName}",
+          cycle.span);
+      // TODO(terry): What if no var definition for a var usage an error?
+      // TODO(terry): Ensure a var definition imported from a different style
+      //              sheet works.
+    }
+
+    // Remove any var definition from the stylesheet that has a cycle.
+    _styleSheets.forEach((styleSheet) =>
+        new RemoveVarDefinitions(cycles).visitStyleSheet(styleSheet));
+
+    // Expand any nested selectors using selector desendant combinator to
+    // signal CSS inheritance notation.
+    _styleSheets.forEach((styleSheet) => new ExpandNestedSelectors()
+        ..visitStyleSheet(styleSheet)
+        ..flatten(styleSheet));
+  }
+
+  List<VarDefinition> findAllCycles() {
+    var cycles = [];
+
+    varDefs.map.values.forEach((value) {
+      if (hasCycle(value.property)) cycles.add(value);
+     });
+
+    // Update our local list of known varDefs remove any varDefs with a cycle.
+    // So the same varDef cycle isn't reported for each style sheet processed.
+    for (var cycle in cycles) {
+      varDefs.map.remove(cycle.property);
+    }
+
+    return cycles;
+  }
+
+  Iterable<VarUsage> variablesOf(Expressions exprs) =>
+      exprs.expressions.where((e) => e is VarUsage);
+
+  bool hasCycle(String varName, {Set<String> visiting, Set<String> visited}) {
+    if (visiting == null) visiting = new Set();
+    if (visited == null) visited = new Set();
+    if (visiting.contains(varName)) return true;
+    if (visited.contains(varName)) return false;
+    visiting.add(varName);
+    visited.add(varName);
+    bool cycleDetected = false;
+    if (varDefs.map[varName] != null) {
+      for (var usage in variablesOf(varDefs.map[varName].expression)) {
+        if (hasCycle(usage.name, visiting: visiting, visited: visited)) {
+          cycleDetected = true;
+          break;
+        }
+      }
+    }
+    visiting.remove(varName);
+    return cycleDetected;
+  }
+
+  // TODO(terry): Need to start supporting @host, custom pseudo elements,
+  //              composition, intrinsics, etc.
+}
+
+
+/** Find all var definitions from a list of stylesheets. */
+class VarDefinitions extends Visitor {
+  /** Map of variable name key to it's definition. */
+  final Map<String, VarDefinition> map = new Map<String, VarDefinition>();
+
+  VarDefinitions(List<StyleSheet> styleSheets) {
+    for (var styleSheet in styleSheets) {
+      visitTree(styleSheet);
+    }
+  }
+
+  void visitVarDefinition(VarDefinition node) {
+    // Replace with latest variable definition.
+    map[node.definedName] = node;
+    super.visitVarDefinition(node);
+  }
+
+  void visitVarDefinitionDirective(VarDefinitionDirective node) {
+    visitVarDefinition(node.def);
+  }
+}
+
+/**
+ * Remove the var definition from the stylesheet where it is defined; if it is
+ * a definition from the list to delete.
+ */
+class RemoveVarDefinitions extends Visitor {
+  final List<VarDefinition> _varDefsToRemove;
+
+  RemoveVarDefinitions(this._varDefsToRemove);
+
+  void visitStyleSheet(StyleSheet ss) {
+    var idx = ss.topLevels.length;
+    while(--idx >= 0) {
+      var topLevel = ss.topLevels[idx];
+      if (topLevel is VarDefinitionDirective &&
+          _varDefsToRemove.contains(topLevel.def)) {
+        ss.topLevels.removeAt(idx);
+      }
+    }
+
+    super.visitStyleSheet(ss);
+  }
+
+  void visitDeclarationGroup(DeclarationGroup node) {
+    var idx = node.declarations.length;
+    while (--idx >= 0) {
+      var decl = node.declarations[idx];
+      if (decl is VarDefinition && _varDefsToRemove.contains(decl)) {
+        node.declarations.removeAt(idx);
+      }
+    }
+
+    super.visitDeclarationGroup(node);
+  }
+}
+
+/**
+ * Traverse all rulesets looking for nested ones.  If a ruleset is in a
+ * declaration group (implies nested selector) then generate new ruleset(s) at
+ * level 0 of CSS using selector inheritance syntax (flattens the nesting).
+ *
+ * How the AST works for a rule [RuleSet] and nested rules.  First of all a
+ * CSS rule [RuleSet] consist of a selector and a declaration e.g.,
+ *
+ *    selector {
+ *      declaration
+ *    }
+ *
+ * AST structure of a [RuleSet] is:
+ *
+ *    RuleSet
+ *       SelectorGroup
+ *         List<Selector>
+ *            List<SimpleSelectorSequence>
+ *              Combinator      // +, >, ~, DESCENDENT, or NONE
+ *              SimpleSelector  // class, id, element, namespace, attribute
+ *        DeclarationGroup
+ *          List                // Declaration or RuleSet
+ *
+ * For the simple rule:
+ *
+ *    div + span { color: red; }
+ *
+ * the AST [RuleSet] is:
+ *
+ *    RuleSet
+ *       SelectorGroup
+ *         List<Selector>
+ *          [0]
+ *            List<SimpleSelectorSequence>
+ *              [0] Combinator = COMBINATOR_NONE
+ *                  ElementSelector (name = div)
+ *              [1] Combinator = COMBINATOR_PLUS
+ *                  ElementSelector (name = span)
+ *        DeclarationGroup
+ *          List                // Declarations or RuleSets
+ *            [0]
+ *              Declaration (property = color, expression = red)
+ *
+ * Usually a SelectorGroup contains 1 Selector.  Consider the selectors:
+ *
+ *    div { color: red; }
+ *    a { color: red; }
+ *
+ * are equivalent to
+ *
+ *    div, a { color : red; }
+ *
+ * In the above the RuleSet would have a SelectorGroup with 2 selectors e.g.,
+ *
+ *    RuleSet
+ *       SelectorGroup
+ *         List<Selector>
+ *          [0]
+ *            List<SimpleSelectorSequence>
+ *              [0] Combinator = COMBINATOR_NONE
+ *                  ElementSelector (name = div)
+ *          [1]
+ *            List<SimpleSelectorSequence>
+ *              [0] Combinator = COMBINATOR_NONE
+ *                  ElementSelector (name = a)
+ *        DeclarationGroup
+ *          List                // Declarations or RuleSets
+ *            [0]
+ *              Declaration (property = color, expression = red)
+ *
+ * For a nested rule e.g.,
+ *
+ *    div {
+ *      color : blue;
+ *      a { color : red; }
+ *    }
+ *
+ * Would map to the follow CSS rules:
+ *
+ *    div { color: blue; }
+ *    div a { color: red; }
+ *
+ * The AST for the former nested rule is:
+ *
+ *    RuleSet
+ *       SelectorGroup
+ *         List<Selector>
+ *          [0]
+ *            List<SimpleSelectorSequence>
+ *              [0] Combinator = COMBINATOR_NONE
+ *                  ElementSelector (name = div)
+ *        DeclarationGroup
+ *          List                // Declarations or RuleSets
+ *            [0]
+ *              Declaration (property = color, expression = blue)
+ *            [1]
+ *              RuleSet
+ *                SelectorGroup
+ *                  List<Selector>
+ *                    [0]
+ *                      List<SimpleSelectorSequence>
+ *                        [0] Combinator = COMBINATOR_NONE
+ *                            ElementSelector (name = a)
+ *                DeclarationGroup
+ *                  List                // Declarations or RuleSets
+ *                    [0]
+ *                      Declaration (property = color, expression = red)
+ *
+ * Nested rules is a terse mechanism to describe CSS inheritance.  The analyzer
+ * will flatten and expand the nested rules to it's flatten strucure.  Using the
+ * all parent [RuleSets] (selector expressions) and applying each nested
+ * [RuleSet] to the list of [Selectors] in a [SelectorGroup].
+ *
+ * Then result is a style sheet where all nested rules have been flatten and
+ * expanded.
+ */
+class ExpandNestedSelectors extends Visitor {
+  /** Parent [RuleSet] if a nested rule otherwise [null]. */
+  RuleSet _parentRuleSet;
+
+  /** Top-most rule if nested rules. */
+  SelectorGroup _topLevelSelectorGroup;
+
+  /** SelectorGroup at each nesting level. */
+  SelectorGroup _nestedSelectorGroup;
+
+  /** Declaration (sans the nested selectors). */
+  DeclarationGroup _flatDeclarationGroup;
+
+  /** Each nested selector get's a flatten RuleSet. */
+  List<RuleSet> _expandedRuleSets = [];
+
+  /** Maping of a nested rule set to the fully expanded list of RuleSet(s). */
+  final Map<RuleSet, List<RuleSet>> _expansions = new Map();
+
+  void visitRuleSet(RuleSet node) {
+    final oldParent = _parentRuleSet;
+
+    var oldNestedSelectorGroups = _nestedSelectorGroup;
+
+    if (_nestedSelectorGroup == null) {
+      // Create top-level selector (may have nested rules).
+      final newSelectors = node.selectorGroup.selectors.toList();
+      _topLevelSelectorGroup = new SelectorGroup(newSelectors, node.span);
+      _nestedSelectorGroup = _topLevelSelectorGroup;
+    } else {
+      // Generate new selector groups from the nested rules.
+      _nestedSelectorGroup = _mergeToFlatten(node);
+    }
+
+    _parentRuleSet = node;
+
+    super.visitRuleSet(node);
+
+    _parentRuleSet = oldParent;
+
+    // Remove nested rules; they're all flatten and in the _expandedRuleSets.
+    node.declarationGroup.declarations.removeWhere((declaration) =>
+        declaration is RuleSet);
+
+    _nestedSelectorGroup = oldNestedSelectorGroups;
+
+    // If any expandedRuleSets and we're back at the top-level rule set then
+    // there were nested rule set(s).
+    if (_parentRuleSet == null) {
+      if (!_expandedRuleSets.isEmpty) {
+        // Remember ruleset to replace with these flattened rulesets.
+        _expansions[node] = _expandedRuleSets;
+        _expandedRuleSets = [];
+      }
+      assert(_flatDeclarationGroup == null);
+      assert(_nestedSelectorGroup == null);
+    }
+  }
+
+  /**
+   * Build up the list of all inherited sequences from the parent selector
+   * [node] is the current nested selector and it's parent is the last entry in
+   * the [_nestedSelectorGroup].
+   */
+  SelectorGroup _mergeToFlatten(RuleSet node) {
+    // Create a new SelectorGroup for this nesting level.
+    var nestedSelectors = _nestedSelectorGroup.selectors;
+    var selectors = node.selectorGroup.selectors;
+
+    // Create a merged set of previous parent selectors and current selectors.
+    var newSelectors = [];
+    for (Selector selector in selectors) {
+      for (Selector nestedSelector in nestedSelectors) {
+        var seq = _mergeNestedSelector(nestedSelector.simpleSelectorSequences,
+            selector.simpleSelectorSequences);
+        newSelectors.add(new Selector(seq, node.span));
+      }
+    }
+
+    return new SelectorGroup(newSelectors, node.span);
+  }
+
+  /**
+   * Merge the nested selector sequences [current] to the [parent] sequences or
+   * substitue any & with the parent selector.
+   */
+  List<SimpleSelectorSequence> _mergeNestedSelector(
+      List<SimpleSelectorSequence> parent,
+      List<SimpleSelectorSequence> current) {
+
+    // If any & operator then the parent selector will be substituted otherwise
+    // the parent selector is pre-pended to the current selector.
+    var hasThis = current.any((s) => s.simpleSelector.isThis);
+
+    var newSequence = [];
+
+    if (!hasThis) {
+      // If no & in the sector group then prefix with the parent selector.
+      newSequence.addAll(parent);
+      newSequence.addAll(_convertToDescendentSequence(current));
+    } else {
+      for (var sequence in current) {
+        if (sequence.simpleSelector.isThis) {
+          // Substitue the & with the parent selector and only use a combinator
+          // descendant if & is prefix by a sequence with an empty name e.g.,
+          // "... + &", "&", "... ~ &", etc.
+          var hasPrefix = !newSequence.isEmpty &&
+              !newSequence.last.simpleSelector.name.isEmpty;
+          newSequence.addAll(
+              hasPrefix ? _convertToDescendentSequence(parent) : parent);
+        } else {
+          newSequence.add(sequence);
+        }
+      }
+    }
+
+    return newSequence;
+  }
+
+  /**
+   * Return selector sequences with first sequence combinator being a
+   * descendant.  Used for nested selectors when the parent selector needs to
+   * be prefixed to a nested selector or to substitute the this (&) with the
+   * parent selector.
+   */
+  List<SimpleSelectorSequence> _convertToDescendentSequence(
+      List<SimpleSelectorSequence> sequences) {
+    if (sequences.isEmpty) return sequences;
+
+    var newSequences = [];
+    var first = sequences.first;
+    newSequences.add(new SimpleSelectorSequence(first.simpleSelector,
+        first.span, TokenKind.COMBINATOR_DESCENDANT));
+    newSequences.addAll(sequences.skip(1));
+
+    return newSequences;
+  }
+
+  void visitDeclarationGroup(DeclarationGroup node) {
+    var span = node.span;
+
+    var currentGroup = new DeclarationGroup([], span);
+
+    var oldGroup = _flatDeclarationGroup;
+    _flatDeclarationGroup = currentGroup;
+
+    var expandedLength = _expandedRuleSets.length;
+
+    super.visitDeclarationGroup(node);
+
+    // We're done with the group.
+    _flatDeclarationGroup = oldGroup;
+
+    // No nested rule to process it's a top-level rule.
+    if (_nestedSelectorGroup == _topLevelSelectorGroup) return;
+
+    // If flatten selector's declaration is empty skip this selector, no need
+    // to emit an empty nested selector.
+    if (currentGroup.declarations.isEmpty) return;
+
+    var selectorGroup = _nestedSelectorGroup;
+
+    // Build new rule set from the nested selectors and declarations.
+    var newRuleSet = new RuleSet(selectorGroup, currentGroup, span);
+
+    // Place in order so outer-most rule is first.
+    if (expandedLength == _expandedRuleSets.length) {
+      _expandedRuleSets.add(newRuleSet);
+    } else {
+      _expandedRuleSets.insert(expandedLength, newRuleSet);
+    }
+  }
+
+  // Record all declarations in a nested selector (Declaration, VarDefinition
+  // and MarginGroup) but not the nested rule in the Declaration.
+
+  void visitDeclaration(Declaration node) {
+    if (_parentRuleSet != null) {
+      _flatDeclarationGroup.declarations.add(node);
+    }
+    super.visitDeclaration(node);
+  }
+
+  void visitVarDefinition(VarDefinition node) {
+    if (_parentRuleSet != null) {
+      _flatDeclarationGroup.declarations.add(node);
+    }
+    super.visitVarDefinition(node);
+  }
+
+  void visitMarginGroup(MarginGroup node) {
+    if (_parentRuleSet != null) {
+      _flatDeclarationGroup.declarations.add(node);
+    }
+    super.visitMarginGroup(node);
+  }
+
+  /**
+   * Replace the rule set that contains nested rules with the flatten rule sets.
+   */
+  void flatten(StyleSheet styleSheet) {
+    // TODO(terry): Iterate over topLevels instead of _expansions it's already
+    //              a map (this maybe quadratic).
+    _expansions.forEach((RuleSet ruleSet, List<RuleSet> newRules) {
+      var index = styleSheet.topLevels.indexOf(ruleSet);
+      if (index == -1) {
+        // Check any @media directives for nested rules and replace them.
+        var found = _MediaRulesReplacer.replace(styleSheet, ruleSet, newRules);
+        assert(found);
+      } else {
+        styleSheet.topLevels.insertAll(index + 1, newRules);
+      }
+    });
+    _expansions.clear();
+  }
+}
+
+class _MediaRulesReplacer extends Visitor {
+  RuleSet _ruleSet;
+  List<RuleSet> _newRules;
+  bool _foundAndReplaced = false;
+
+  /**
+   * Look for the [ruleSet] inside of an @media directive; if found then replace
+   * with the [newRules].  If [ruleSet] is found and replaced return true.
+   */
+  static bool replace(StyleSheet styleSheet, RuleSet ruleSet,
+                      List<RuleSet>newRules) {
+    var visitor = new _MediaRulesReplacer(ruleSet, newRules);
+    visitor.visitStyleSheet(styleSheet);
+    return visitor._foundAndReplaced;
+  }
+
+  _MediaRulesReplacer(this._ruleSet, this._newRules);
+
+  visitMediaDirective(MediaDirective node) {
+    var index = node.rulesets.indexOf(_ruleSet);
+    if (index != -1) {
+      node.rulesets.insertAll(index + 1, _newRules);
+      _foundAndReplaced = true;
+    }
+  }
+}
diff --git a/pkg/csslib/lib/src/css_printer.dart b/pkg/csslib/lib/src/css_printer.dart
new file mode 100644
index 0000000..b8000b7
--- /dev/null
+++ b/pkg/csslib/lib/src/css_printer.dart
@@ -0,0 +1,476 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.visitor;
+
+/**
+ * Visitor that produces a formatted string representation of the CSS tree.
+ */
+class CssPrinter extends Visitor {
+  StringBuffer _buff = new StringBuffer();
+  bool prettyPrint = true;
+
+  /**
+   * Walk the [tree] Stylesheet. [pretty] if true emits line breaks, extra
+   * spaces, friendly property values, etc., if false emits compacted output.
+   */
+  void visitTree(StyleSheet tree, {bool pretty: false}) {
+    prettyPrint = pretty;
+    _buff = new StringBuffer();
+    visitStyleSheet(tree);
+  }
+
+  /** Appends [str] to the output buffer. */
+  void emit(String str) {
+    _buff.write(str);
+  }
+
+  /** Returns the output buffer. */
+  String toString() => _buff.toString().trim();
+
+  String get _newLine => prettyPrint ? '\n' : ' ';
+  String get _sp => prettyPrint ? ' ' : '';
+
+  // TODO(terry): When adding obfuscation we'll need isOptimized (compact w/
+  //              obufuscation) and have isTesting (compact no obfuscation) and
+  //              isCompact would be !prettyPrint.  We'll need another boolean
+  //              flag for obfuscation.
+  bool get _isTesting => !prettyPrint;
+
+  void visitCssComment(CssComment node) {
+    emit('/* ${node.comment} */');
+  }
+
+  void visitCommentDefinition(CommentDefinition node) {
+    emit('<!-- ${node.comment} -->');
+  }
+
+  void visitMediaExpression(MediaExpression node) {
+    emit(node.andOperator ? ' AND ' : ' ');
+    emit('(${node.mediaFeature}:');
+    visitExpressions(node.exprs);
+    emit(')');
+  }
+
+  void visitMediaQuery(MediaQuery query) {
+    var unary = query.hasUnary ? ' ${query.unary}' : '';
+    var mediaType = query.hasMediaType ? ' ${query.mediaType}' : '';
+    emit('$unary$mediaType');
+    for (var expression in query.expressions) {
+      visitMediaExpression(expression);
+    }
+  }
+
+  void emitMediaQueries(queries) {
+    var queriesLen = queries.length;
+    for (var i = 0; i < queriesLen; i++) {
+      var query = queries[i];
+      if (query.hasMediaType && i > 0) emit(',');
+      visitMediaQuery(query);
+    }
+  }
+
+  void visitMediaDirective(MediaDirective node) {
+    emit(' @media');
+    emitMediaQueries(node.mediaQueries);
+    emit(' {');
+    for (var ruleset in node.rulesets) {
+      ruleset.visit(this);
+    }
+    emit('$_newLine\}');
+  }
+
+  void visitHostDirective(HostDirective node) {
+    emit('\n@host {');
+    for (var ruleset in node.rulesets) {
+      ruleset.visit(this);
+    }
+    emit('$_newLine\}');
+  }
+
+  /**
+   *  @page : pseudoPage {
+   *    decls
+   *  }
+   */
+  void visitPageDirective(PageDirective node) {
+    emit('$_newLine@page');
+    if (node.hasIdent || node.hasPseudoPage) {
+      if (node.hasIdent) emit(' ');
+      emit(node._ident);
+      emit(node.hasPseudoPage ? ':${node._pseudoPage}' : '');
+    }
+    emit(' ');
+
+    var declsMargin = node._declsMargin;
+    int declsMarginLength = declsMargin.length;
+    for (var i = 0; i < declsMarginLength; i++) {
+      if (i > 0) emit(_newLine);
+      emit('{$_newLine');
+      declsMargin[i].visit(this);
+      emit('}');
+    }
+  }
+
+  /** @charset "charset encoding" */
+  void visitCharsetDirective(CharsetDirective node) {
+    emit('$_newLine@charset "${node.charEncoding}";');
+  }
+
+  void visitImportDirective(ImportDirective node) {
+    bool isStartingQuote(String ch) => ('\'"'.indexOf(ch[0]) >= 0);
+
+    if (_isTesting) {
+      // Emit assuming url() was parsed; most suite tests use url function.
+      emit(' @import url(${node.import})');
+    } else if (isStartingQuote(node.import)) {
+      emit(' @import ${node.import}');
+    } else {
+      // url(...) isn't needed only a URI can follow an @import directive; emit
+      // url as a string.
+      emit(' @import "${node.import}"');
+    }
+    emitMediaQueries(node.mediaQueries);
+    emit(';');
+  }
+
+  void visitKeyFrameDirective(KeyFrameDirective node) {
+    emit('$_newLine${node.keyFrameName} ');
+    node._name.visit(this);
+    emit('$_sp{$_newLine');
+    for (final block in node._blocks) {
+      block.visit(this);
+    }
+    emit('}');
+  }
+
+  void visitFontFaceDirective(FontFaceDirective node) {
+    emit('$_newLine@font-face ');
+    emit('$_sp{$_newLine');
+    node._declarations.visit(this);
+    emit('}');
+  }
+
+  void visitKeyFrameBlock(KeyFrameBlock node) {
+    emit('$_sp$_sp');
+    node._blockSelectors.visit(this);
+    emit('$_sp{$_newLine');
+    node._declarations.visit(this);
+    emit('$_sp$_sp}$_newLine');
+  }
+
+  void visitStyletDirective(StyletDirective node) {
+    emit('/* @stylet export as ${node._dartClassName} */\n');
+  }
+
+  void visitNamespaceDirective(NamespaceDirective node) {
+    bool isStartingQuote(String ch) => ('\'"'.indexOf(ch) >= 0);
+
+    if (isStartingQuote(node._uri)) {
+      emit(' @namespace ${node.prefix}"${node._uri}"');
+    } else {
+      if (_isTesting) {
+        // Emit exactly was we parsed.
+        emit(' @namespace ${node.prefix}url(${node._uri})');
+      } else {
+        // url(...) isn't needed only a URI can follow a:
+        //    @namespace prefix directive.
+        emit(' @namespace ${node.prefix}${node._uri}');
+      }
+    }
+    emit(';');
+  }
+
+  void visitVarDefinitionDirective(VarDefinitionDirective node) {
+    visitVarDefinition(node.def);
+    emit(';$_newLine');
+  }
+
+  void visitRuleSet(RuleSet node) {
+    emit("$_newLine");
+    node._selectorGroup.visit(this);
+    emit(" {$_newLine");
+    node._declarationGroup.visit(this);
+    emit("}");
+  }
+
+  void visitDeclarationGroup(DeclarationGroup node) {
+    var declarations = node._declarations;
+    var declarationsLength = declarations.length;
+    for (var i = 0; i < declarationsLength; i++) {
+      if (i > 0) emit(_newLine);
+      emit("$_sp$_sp");
+      declarations[i].visit(this);
+      emit(";");
+    }
+    if (declarationsLength > 0) emit(_newLine);
+  }
+
+  void visitMarginGroup(MarginGroup node) {
+    var margin_sym_name =
+        TokenKind.idToValue(TokenKind.MARGIN_DIRECTIVES, node.margin_sym);
+
+    emit("@$margin_sym_name {$_newLine");
+
+    visitDeclarationGroup(node);
+
+    emit("}$_newLine");
+  }
+
+  void visitDeclaration(Declaration node) {
+    String importantAsString() => node.important ? '$_sp!important' : '';
+
+    emit("${node.property}: ");
+    node._expression.visit(this);
+
+    emit("${importantAsString()}");
+  }
+
+  void visitVarDefinition(VarDefinition node) {
+    emit("var-${node.definedName}: ");
+    node._expression.visit(this);
+  }
+
+  void visitSelectorGroup(SelectorGroup node) {
+    var selectors = node._selectors;
+    var selectorsLength = selectors.length;
+    for (var i = 0; i < selectorsLength; i++) {
+      if (i > 0) emit(',$_sp');
+      selectors[i].visit(this);
+    }
+  }
+
+  void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+    emit('${node._combinatorToString}');
+    node._selector.visit(this);
+  }
+
+  void visitSimpleSelector(SimpleSelector node) {
+    emit(node.name);
+  }
+
+  void visitNamespaceSelector(NamespaceSelector node) {
+    emit("${node.namespace}|${node.nameAsSimpleSelector.name}");
+  }
+
+  void visitElementSelector(ElementSelector node) {
+    emit("${node.name}");
+  }
+
+  void visitAttributeSelector(AttributeSelector node) {
+    emit("[${node.name}${node.matchOperator()}${node.valueToString()}]");
+  }
+
+  void visitIdSelector(IdSelector node) {
+    emit("#${node.name}");
+  }
+
+  void visitClassSelector(ClassSelector node) {
+    emit(".${node.name}");
+  }
+
+  void visitPseudoClassSelector(PseudoClassSelector node) {
+    emit(":${node.name}");
+  }
+
+  void visitPseudoElementSelector(PseudoElementSelector node) {
+    emit("::${node.name}");
+  }
+
+  void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
+    emit(":${node.name}(");
+    node.expression.visit(this);
+    emit(')');
+  }
+
+  void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) {
+    emit("::${node.name}(");
+    node.expression.visit(this);
+    emit(')');
+  }
+
+  void visitNegationSelector(NegationSelector node) {
+    emit(':not(');
+    node.negationArg.visit(this);
+    emit(')');
+  }
+
+  void visitSelectorExpression(SelectorExpression node) {
+    var expressions = node._expressions;
+    var expressionsLength = expressions.length;
+    for (var i = 0; i < expressionsLength; i++) {
+      // Add space seperator between terms without an operator.
+      var expression = expressions[i];
+      expression.visit(this);
+    }
+  }
+
+  void visitUnicodeRangeTerm(UnicodeRangeTerm node) {
+    if (node.hasSecond) {
+      emit("U+${node.first}-${node.second}");
+    } else {
+      emit("U+${node.first}");
+    }
+  }
+
+  void visitLiteralTerm(LiteralTerm node) {
+    emit(node.text);
+  }
+
+  void visitHexColorTerm(HexColorTerm node) {
+    var mappedName;
+    if (_isTesting && (node.value is! BAD_HEX_VALUE)) {
+      mappedName = TokenKind.hexToColorName(node.value);
+    }
+    if (mappedName == null) {
+      mappedName = '#${node.text}';
+    }
+
+    emit(mappedName);
+  }
+
+  void visitNumberTerm(NumberTerm node) {
+    visitLiteralTerm(node);
+  }
+
+  void visitUnitTerm(UnitTerm node) {
+    emit(node.toString());
+  }
+
+  void visitLengthTerm(LengthTerm node) {
+    emit(node.toString());
+  }
+
+  void visitPercentageTerm(PercentageTerm node) {
+    emit('${node.text}%');
+  }
+
+  void visitEmTerm(EmTerm node) {
+    emit('${node.text}em');
+  }
+
+  void visitExTerm(ExTerm node) {
+    emit('${node.text}ex');
+  }
+
+  void visitAngleTerm(AngleTerm node) {
+    emit(node.toString());
+  }
+
+  void visitTimeTerm(TimeTerm node) {
+    emit(node.toString());
+  }
+
+  void visitFreqTerm(FreqTerm node) {
+    emit(node.toString());
+  }
+
+  void visitFractionTerm(FractionTerm node) {
+    emit('${node.text}fr');
+  }
+
+  void visitUriTerm(UriTerm node) {
+    emit('url("${node.text}")');
+  }
+
+  void visitResolutionTerm(ResolutionTerm node) {
+    emit(node.toString());
+  }
+
+  void visitViewportTerm(ViewportTerm node) {
+    emit(node.toString());
+  }
+
+  void visitFunctionTerm(FunctionTerm node) {
+    // TODO(terry): Optimize rgb to a hexcolor.
+    emit('${node.text}(');
+    node._params.visit(this);
+    emit(')');
+  }
+
+  void visitGroupTerm(GroupTerm node) {
+    emit('(');
+    var terms = node._terms;
+    var termsLength = terms.length;
+    for (var i = 0; i < termsLength; i++) {
+      if (i > 0) emit('$_sp');
+      terms[i].visit(this);
+    }
+    emit(')');
+  }
+
+  void visitItemTerm(ItemTerm node) {
+    emit('[${node.text}]');
+  }
+
+  void visitIE8Term(IE8Term node) {
+    visitLiteralTerm(node);
+  }
+
+  void visitOperatorSlash(OperatorSlash node) {
+    emit('/');
+  }
+
+  void visitOperatorComma(OperatorComma node) {
+    emit(',');
+  }
+
+  void visitOperatorPlus(OperatorPlus node) {
+    emit('+');
+  }
+
+  void visitOperatorMinus(OperatorMinus node) {
+    emit('-');
+  }
+
+  void visitVarUsage(VarUsage node) {
+    emit('var(${node.name}');
+    if (!node.defaultValues.isEmpty) {
+      emit(',');
+      for (var defaultValue in node.defaultValues) {
+        emit(' ');
+        defaultValue.visit(this);
+      }
+    }
+    emit(')');
+  }
+
+  void visitExpressions(Expressions node) {
+    var expressions = node.expressions;
+    var expressionsLength = expressions.length;
+    for (var i = 0; i < expressionsLength; i++) {
+      // Add space seperator between terms without an operator.
+      // TODO(terry): Should have a BinaryExpression to solve this problem.
+      var expression = expressions[i];
+      if (i > 0 &&
+          !(expression is OperatorComma || expression is OperatorSlash)) {
+        emit(' ');
+      }
+      expression.visit(this);
+    }
+  }
+
+  void visitBinaryExpression(BinaryExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitUnaryExpression(UnaryExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitIdentifier(Identifier node) {
+    emit(node.name);
+  }
+
+  void visitWildcard(Wildcard node) {
+    emit('*');
+  }
+
+  void visitDartStyleExpression(DartStyleExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+}
diff --git a/pkg/csslib/lib/src/messages.dart b/pkg/csslib/lib/src/messages.dart
new file mode 100644
index 0000000..3c9f3fc
--- /dev/null
+++ b/pkg/csslib/lib/src/messages.dart
@@ -0,0 +1,129 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library csslib.src.messages;
+
+import 'package:logging/logging.dart' show Level;
+import 'package:source_maps/span.dart' show Span;
+
+import 'package:csslib/parser.dart';
+
+import 'options.dart';
+
+// TODO(terry): Remove the global messages, use some object that tracks
+//              compilation state.
+
+/** The global [Messages] for tracking info/warnings/messages. */
+Messages messages;
+
+// Color constants used for generating messages.
+final String GREEN_COLOR = '\u001b[32m';
+final String RED_COLOR = '\u001b[31m';
+final String MAGENTA_COLOR = '\u001b[35m';
+final String NO_COLOR = '\u001b[0m';
+
+/** Map between error levels and their display color. */
+final Map<Level, String> _ERROR_COLORS = (() {
+  var colorsMap = new Map<Level, String>();
+  colorsMap[Level.SEVERE] = RED_COLOR;
+  colorsMap[Level.WARNING] = MAGENTA_COLOR;
+  colorsMap[Level.INFO] = GREEN_COLOR;
+  return colorsMap;
+})();
+
+/** Map between error levels and their friendly name. */
+final Map<Level, String> _ERROR_LABEL = (() {
+  var labels = new Map<Level, String>();
+  labels[Level.SEVERE] = 'error';
+  labels[Level.WARNING] = 'warning';
+  labels[Level.INFO] = 'info';
+  return labels;
+})();
+
+/** A single message from the compiler. */
+class Message {
+  final Level level;
+  final String message;
+  final Span span;
+  final bool useColors;
+
+  Message(this.level, this.message, {Span span, bool useColors: false})
+      : this.span = span, this.useColors = useColors;
+
+  String toString() {
+    var output = new StringBuffer();
+    bool colors = useColors && _ERROR_COLORS.containsKey(level);
+    var levelColor =  _ERROR_COLORS[level];
+    if (colors) output.write(levelColor);
+    output..write(_ERROR_LABEL[level])..write(' ');
+    if (colors) output.write(NO_COLOR);
+
+    if (span == null) {
+      output.write(message);
+    } else {
+      output.write(span.getLocationMessage(message, useColors: colors,
+          color: levelColor));
+    }
+
+    return output.toString();
+  }
+}
+
+typedef void PrintHandler(Object obj);
+
+/**
+ * This class tracks and prints information, warnings, and errors emitted by the
+ * compiler.
+ */
+class Messages {
+  /** Called on every error. Set to blank function to supress printing. */
+  final PrintHandler printHandler;
+
+  final PreprocessorOptions options;
+
+  final List<Message> messages = <Message>[];
+
+  Messages({PreprocessorOptions options, this.printHandler: print})
+      : options = options != null ? options : new PreprocessorOptions();
+
+  /** Report a compile-time CSS error. */
+  void error(String message, Span span) {
+    var msg = new Message(Level.SEVERE, message, span: span,
+        useColors: options.useColors);
+
+    messages.add(msg);
+
+    printHandler(msg);
+  }
+
+  /** Report a compile-time CSS warning. */
+  void warning(String message, Span span) {
+    if (options.warningsAsErrors) {
+      error(message, span);
+    } else {
+      var msg = new Message(Level.WARNING, message, span: span,
+          useColors: options.useColors);
+
+      messages.add(msg);
+    }
+  }
+
+  /** Report and informational message about what the compiler is doing. */
+  void info(String message, Span span) {
+    var msg = new Message(Level.INFO, message, span: span,
+        useColors: options.useColors);
+
+    messages.add(msg);
+
+    if (options.verbose) printHandler(msg);
+  }
+
+  /** Merge [newMessages] to this message lsit. */
+  void mergeMessages(Messages newMessages) {
+    messages.addAll(newMessages.messages);
+    newMessages.messages.where((message) =>
+        message.level.value == Level.SEVERE || options.verbose)
+        .forEach((message) { printHandler(message); });
+  }
+}
diff --git a/pkg/csslib/lib/src/options.dart b/pkg/csslib/lib/src/options.dart
new file mode 100644
index 0000000..a62ef71
--- /dev/null
+++ b/pkg/csslib/lib/src/options.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library csslib.src.options;
+
+import 'package:args/args.dart';
+
+class PreprocessorOptions {
+  /** Report warnings as errors. */
+  final bool warningsAsErrors;
+
+  /** Throw an exception on warnings (not used by command line tool). */
+  final bool throwOnWarnings;
+
+  /** Throw an exception on errors (not used by command line tool). */
+  final bool throwOnErrors;
+
+  /** True to show informational messages. The `--verbose` flag. */
+  final bool verbose;
+
+  /** True to show warning messages for bad CSS.  The '--checked' flag. */
+  final bool checked;
+
+  // TODO(terry): Add mixin support and nested rules.
+  /**
+   * Subset of Less commands enabled; disable with '--no-less'.
+   * Less syntax supported:
+   * - @name at root level statically defines variables resolved at compilation
+   * time.  Essentially a directive e.g., @var-name.
+   */
+  final bool lessSupport;
+
+  /** Whether to use colors to print messages on the terminal. */
+  final bool useColors;
+
+  /** File to process by the compiler. */
+  String inputFile;
+
+  // We could make this faster, if it ever matters.
+  factory PreprocessorOptions() => parse(['']);
+
+  PreprocessorOptions.fromArgs(ArgResults args)
+    : warningsAsErrors = args['warnings_as_errors'],
+      throwOnWarnings = args['throw_on_warnings'],
+      throwOnErrors = args['throw_on_errors'],
+      verbose = args['verbose'],
+      checked = args['checked'],
+      lessSupport = args['less'],
+      useColors = args['colors'],
+      inputFile = args.rest.length > 0 ? args.rest[0] : null;
+
+  // tool.dart [options...] <css file>
+  static PreprocessorOptions parse(List<String> arguments) {
+    var parser = new ArgParser()
+      ..addFlag('verbose', abbr: 'v', defaultsTo: false, negatable: false,
+          help: 'Display detail info')
+      ..addFlag('checked', defaultsTo: false, negatable: false,
+          help: 'Validate CSS values invalid value display a warning message')
+      ..addFlag('less', defaultsTo: true, negatable: true,
+          help: 'Supports subset of Less syntax')
+      ..addFlag('suppress_warnings', defaultsTo: true,
+          help: 'Warnings not displayed')
+      ..addFlag('warnings_as_errors', defaultsTo: false,
+          help: 'Warning handled as errors')
+      ..addFlag('throw_on_errors', defaultsTo: false,
+          help: 'Throw on errors encountered')
+      ..addFlag('throw_on_warnings', defaultsTo: false,
+          help: 'Throw on warnings encountered')
+      ..addFlag('colors', defaultsTo: true,
+          help: 'Display errors/warnings in colored text')
+      ..addFlag('help', abbr: 'h', defaultsTo: false, negatable: false,
+          help: 'Displays this help message');
+
+    try {
+      var results = parser.parse(arguments);
+      if (results['help'] || results.rest.length == 0) {
+        showUsage(parser);
+        return null;
+      }
+      return new PreprocessorOptions.fromArgs(results);
+    } on FormatException catch (e) {
+      print(e.message);
+      showUsage(parser);
+      return null;
+    }
+  }
+
+  static showUsage(parser) {
+    print('Usage: css [options...] input.css');
+    print(parser.getUsage());
+  }
+
+}
diff --git a/pkg/csslib/lib/src/property.dart b/pkg/csslib/lib/src/property.dart
new file mode 100644
index 0000000..8dc4dcb
--- /dev/null
+++ b/pkg/csslib/lib/src/property.dart
@@ -0,0 +1,1250 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Representations of CSS styles. */
+
+part of csslib.parser;
+
+// TODO(terry): Prune down this file we do need some of the code in this file
+//              for darker, lighter, how to represent a Font, etc but alot of
+//              the complexity can be removed.
+//              See https://github.com/dart-lang/csslib/issues/7
+
+/**
+ * Base for all style properties (e.g., Color, Font, Border, Margin, etc.)
+ */
+abstract class _StyleProperty {
+  /**
+   * Returns the expression part of a CSS declaration.  Declaration is:
+   *
+   *     property:expression;
+   *
+   * E.g., if property is color then expression could be rgba(255,255,0) the
+   *       CSS declaration would be 'color:rgba(255,255,0);'.
+   *
+   * then _cssExpression would return 'rgba(255,255,0)'.  See
+   * <http://www.w3.org/TR/CSS21/grammar.html>
+   */
+  String get cssExpression;
+}
+
+
+/**
+ * Base interface for Color, HSL and RGB.
+ */
+abstract class ColorBase {
+  /**
+   * Canonical form for color #rrggbb with alpha blending (0.0 == full
+   * transparency and 1.0 == fully opaque). If _argb length is 6 it's an
+   * rrggbb otherwise it's aarrggbb.
+   */
+  String toHexArgbString();
+
+  /**
+   * Return argb as a value (int).
+   */
+  int get argbValue;
+}
+
+
+/**
+ * General purpse Color class.  Represent a color as an ARGB value that can be
+ * converted to and from num, hex string, hsl, hsla, rgb, rgba and SVG pre-
+ * defined color constant.
+ */
+class Color implements _StyleProperty, ColorBase {
+  // If _argb length is 6 it's an rrggbb otherwise it's aarrggbb.
+  final String _argb;
+
+  // TODO(terry): Look at reducing Rgba and Hsla classes as factories for
+  //              converting from Color to an Rgba or Hsla for reading only.
+  //              Usefulness of creating an Rgba or Hsla is limited.
+
+  /**
+   * Create a color with an integer representing the rgb value of red, green,
+   * and blue.  The value 0xffffff is the color white #ffffff (CSS style).
+   * The [rgb] value of 0xffd700 would map to #ffd700 or the constant
+   * Color.gold, where ff is red intensity, d7 is green intensity, and 00 is
+   * blue intensity.
+   */
+  Color(int rgb, [num alpha]) :
+    this._argb = Color._rgbToArgbString(rgb, alpha);
+
+  /**
+   * RGB takes three values. The [red], [green], and [blue] parameters are
+   * the intensity of those components where '0' is the least and '256' is the
+   * greatest.
+   *
+   * If [alpha] is provided, it is the level of translucency which ranges from
+   * '0' (completely transparent) to '1.0' (completely opaque).  It will
+   * internally be mapped to an int between '0' and '255' like the other color
+   * components.
+   */
+  Color.createRgba(int red, int green, int blue, [num alpha]) :
+      this._argb = Color.convertToHexString(Color._clamp(red, 0, 255),
+          Color._clamp(green, 0, 255),
+          Color._clamp(blue, 0, 255),
+          alpha != null ? Color._clamp(alpha, 0, 1) : alpha);
+
+  /**
+   * Creates a new color from a CSS color string. For more information, see
+   * <https://developer.mozilla.org/en/CSS/color>.
+   */
+  Color.css(String color) :
+      this._argb = Color._convertCssToArgb(color);
+
+  // TODO(jmesserly): I found the use of percents a bit suprising.
+  /**
+   * HSL takes three values.  The [hueDegree] degree on the color wheel; '0' is
+   * the least and '100' is the greatest.  The value '0' or '360' is red, '120'
+   * is green, '240' is blue. Numbers in between reflect different shades.
+   * The [saturationPercent] percentage; where'0' is the least and '100' is the
+   * greatest (100 represents full color).  The [lightnessPercent] percentage;
+   * where'0' is the least and '100' is the greatest.  The value 0 is dark or
+   * black, 100 is light or white and 50 is a medium lightness.
+   *
+   * If [alpha] is provided, it is the level of translucency which ranges from
+   * '0' (completely transparent foreground) to '1.0' (completely opaque
+   * foreground).
+   */
+  Color.createHsla(num hueDegree, num saturationPercent, num lightnessPercent,
+      [num alpha]) :
+          this._argb = new Hsla(Color._clamp(hueDegree, 0, 360) / 360,
+          Color._clamp(saturationPercent, 0, 100) / 100,
+          Color._clamp(lightnessPercent, 0, 100) / 100,
+          alpha != null ? Color._clamp(alpha, 0, 1) : alpha).toHexArgbString();
+
+  /**
+   * The hslaRaw takes three values.  The [hue] degree on the color wheel; '0'
+   * is the least and '1' is the greatest.  The value '0' or '1' is red, the
+   * ratio of 120/360 is green, and the ratio of 240/360 is blue.  Numbers in
+   * between reflect different shades.  The [saturation] is a percentage; '0'
+   * is the least and '1' is the greatest.  The value of '1' is equivalent to
+   * 100% (full colour).  The [lightness] is a percentage; '0' is the least and
+   * '1' is the greatest.  The value of '0' is dark (black), the value of '1'
+   * is light (white), and the value of '.50' is a medium lightness.
+   *
+   * The fourth optional parameter is:
+   *   [alpha]      level of translucency range of values is 0..1, zero is a
+   *                completely transparent foreground and 1 is a completely
+   *                opaque foreground.
+   */
+  Color.hslaRaw(num hue, num saturation, num lightness, [num alpha]) :
+    this._argb = new Hsla(Color._clamp(hue, 0, 1),
+          Color._clamp(saturation, 0, 1),
+          Color._clamp(lightness, 0, 1),
+          alpha != null ? Color._clamp(alpha, 0, 1) : alpha).toHexArgbString();
+
+  /**
+   * Generate a real constant for pre-defined colors (no leading #).
+   */
+  const Color.hex(this._argb);
+
+  // TODO(jmesserly): this is needed by the example so leave it exposed for now.
+  String toString() => cssExpression;
+
+  // TODO(terry): Regardless of how color is set (rgb, num, css or hsl) we'll
+  //              always return a rgb or rgba loses fidelity when debugging in
+  //              CSS if user uses hsl and would like to edit as hsl, etc.  If
+  //              this is an issue we should keep the original value and not re-
+  //              create the CSS from the normalized value.
+  String get cssExpression {
+    if (_argb.length == 6) {
+      return "#$_argb";         // RGB only, no alpha blending.
+    } else {
+      num alpha = Color.hexToInt(_argb.substring(0, 2));
+      String a = (alpha / 255).toStringAsPrecision(2);
+      int r = Color.hexToInt(_argb.substring(2, 4));
+      int g = Color.hexToInt(_argb.substring(4, 6));
+      int b = Color.hexToInt(_argb.substring(6, 8));
+      return "rgba($r,$g,$b,$a)";
+    }
+  }
+
+  Rgba get rgba {
+    int nextIndex = 0;
+    num a;
+    if (_argb.length == 8) {
+      // Get alpha blending value 0..255
+      int alpha = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+      // Convert to value from 0..1
+      a = double.parse((alpha / 255).toStringAsPrecision(2));
+      nextIndex += 2;
+    }
+    int r = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+    nextIndex += 2;
+    int g = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+    nextIndex += 2;
+    int b = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+    return new Rgba(r, g, b, a);
+  }
+
+  Hsla get hsla => new Hsla.fromRgba(rgba);
+
+  int get argbValue => Color.hexToInt(_argb);
+
+  bool operator ==(Object other) => Color.equal(this, other);
+
+  String toHexArgbString() => _argb;
+
+  Color darker(num amount) {
+    Rgba newRgba = Color._createNewTintShadeFromRgba(rgba, -amount);
+    return new Color.hex("${newRgba.toHexArgbString()}");
+  }
+
+  Color lighter(num amount) {
+    Rgba newRgba = Color._createNewTintShadeFromRgba(rgba, amount);
+    return new Color.hex("${newRgba.toHexArgbString()}");
+  }
+
+  static bool equal(ColorBase curr, Object other) {
+    if (other is Color) {
+      Color o = other;
+      return o.toHexArgbString() == curr.toHexArgbString();
+    } else if (other is Rgba) {
+      Rgba rgb = other;
+      return rgb.toHexArgbString() == curr.toHexArgbString();
+    } else if (other is Hsla) {
+      Hsla hsla = other;
+      return hsla.toHexArgbString() == curr.toHexArgbString();
+    } else {
+      return false;
+    }
+  }
+
+  int get hashCode => _argb.hashCode;
+
+  // Conversion routines:
+
+  static String _rgbToArgbString(int rgba, num alpha) {
+    int a;
+    // If alpha is defined then adjust from 0..1 to 0..255 value, if not set
+    // then a is left as undefined and passed to convertToHexString.
+    if (alpha != null) {
+      a = (Color._clamp(alpha, 0, 1) * 255).round();
+    }
+
+    int r = (rgba & 0xff0000) >> 0x10;
+    int g = (rgba & 0xff00) >> 8;
+    int b = rgba & 0xff;
+
+    return Color.convertToHexString(r, g, b, a);
+  }
+
+  static const int _rgbCss = 1;
+  static const int _rgbaCss = 2;
+  static const int _hslCss = 3;
+  static const int _hslaCss = 4;
+  /**
+   * Parse CSS expressions of the from #rgb, rgb(r,g,b), rgba(r,g,b,a),
+   * hsl(h,s,l), hsla(h,s,l,a) and SVG colors (e.g., darkSlateblue, etc.) and
+   * convert to argb.
+   */
+  static String _convertCssToArgb(String value) {
+    // TODO(terry): Better parser/regex for converting CSS properties.
+    String color = value.trim().replaceAll("\\s", "");
+    if (color[0] == '#') {
+      String v = color.substring(1);
+      Color.hexToInt(v);              // Valid hexadecimal, throws if not.
+      return v;
+    } else if (color.length > 0 && color[color.length - 1] == ')') {
+      int type;
+      if (color.indexOf("rgb(") == 0 || color.indexOf("RGB(") == 0) {
+        color = color.substring(4);
+        type = _rgbCss;
+      } else if (color.indexOf("rgba(") == 0 || color.indexOf("RGBA(") == 0) {
+        type = _rgbaCss;
+        color = color.substring(5);
+      } else if (color.indexOf("hsl(") == 0 || color.indexOf("HSL(") == 0) {
+        type = _hslCss;
+        color = color.substring(4);
+      } else if (color.indexOf("hsla(") == 0 || color.indexOf("HSLA(") == 0) {
+        type = _hslaCss;
+        color = color.substring(5);
+      } else {
+        throw new UnsupportedError('CSS property not implemented');
+      }
+
+      color = color.substring(0, color.length - 1);     // Strip close paren.
+
+      var args = <num>[];
+      List<String> params = color.split(",");
+      for (String param in params) {
+        args.add(double.parse(param));
+      }
+      switch (type) {
+        case _rgbCss:
+          return Color.convertToHexString(args[0], args[1], args[2]);
+        case _rgbaCss:
+          return Color.convertToHexString(args[0], args[1], args[2], args[3]);
+        case _hslCss:
+          return new Hsla(args[0], args[1], args[2]).toHexArgbString();
+        case _hslaCss:
+          return new Hsla(args[0], args[1], args[2],
+              args[3]).toHexArgbString();
+        default:
+          // Type not defined UnsupportedOperationException should have thrown.
+          assert(true);
+          break;
+      }
+    }
+  }
+
+  /**
+   * [hex] hexadecimal string to convert to scalar.
+   * returns hexadecimal number as an integer.
+   * throws BadNumberFormatException if [hex] isn't a valid hexadecimal number.
+   */
+  // TODO(terry): Should be part of Dart standard library see bug
+  // <http://code.google.com/p/dart/issues/detail?id=2624>
+  static int hexToInt(String hex) {
+    int val = 0;
+
+    int len = hex.length;
+    for (int i = 0; i < len; i++) {
+      int hexDigit = hex.codeUnitAt(i);
+      if (hexDigit >= 48 && hexDigit <= 57) {
+        val += (hexDigit - 48) * (1 << (4 * (len - 1 - i)));
+      } else if (hexDigit >= 65 && hexDigit <= 70) {
+        // A..F
+        val += (hexDigit - 55) * (1 << (4 * (len - 1 - i)));
+      } else if (hexDigit >= 97 && hexDigit <= 102) {
+        // a..f
+        val += (hexDigit - 87) * (1 << (4 * (len - 1 - i)));
+      } else {
+        throw throw new FormatException("Bad hexadecimal value");
+      }
+    }
+
+    return val;
+  }
+
+  static String convertToHexString(int r, int g, int b, [num a]) {
+    String rHex = Color._numAs2DigitHex(Color._clamp(r, 0, 255));
+    String gHex = Color._numAs2DigitHex(Color._clamp(g, 0, 255));
+    String bHex = Color._numAs2DigitHex(Color._clamp(b, 0, 255));
+    String aHex = (a != null) ?
+        Color._numAs2DigitHex((Color._clamp(a, 0, 1) * 255).round()) : "";
+
+    // TODO(terry) 15.toRadixString(16) return 'F' on Dartium not f as in JS.
+    //             bug: <http://code.google.com/p/dart/issues/detail?id=2670>
+    return "$aHex$rHex$gHex$bHex".toLowerCase();
+  }
+
+  static String _numAs2DigitHex(num v) {
+    // TODO(terry): v.toInt().toRadixString instead of v.toRadixString
+    //              Bug <http://code.google.com/p/dart/issues/detail?id=2671>.
+    String hex = v.toInt().toRadixString(16);
+    if (hex.length == 1) {
+      hex = "0${hex}";
+    }
+    return hex;
+  }
+
+  static num _clamp(num value, num min, num max) =>
+      math.max(math.min(max, value), min);
+
+  /**
+   * Change the tint (make color lighter) or shade (make color darker) of all
+   * parts of [rgba] (r, g and b).  The [amount] is percentage darker between
+   * -1 to 0 for darker and 0 to 1 for lighter; '0' is no change.  The [amount]
+   * will darken or lighten the rgb values; it will not change the alpha value.
+   * If [amount] is outside of the value -1 to +1 then [amount] is changed to
+   * either the min or max direction -1 or 1.
+   *
+   * Darker will approach the color #000000 (black) and lighter will approach
+   * the color #ffffff (white).
+   */
+  static Rgba _createNewTintShadeFromRgba(Rgba rgba, num amount) {
+    int r, g, b;
+    num tintShade = Color._clamp(amount, -1, 1);
+    if (amount < 0 && rgba.r == 255 && rgba.g == 255 && rgba.b == 255) {
+      // TODO(terry): See TODO in _changeTintShadeColor; eliminate this test
+      //              by converting to HSL and adjust lightness although this
+      //              is fastest lighter/darker algorithm.
+      // Darkening white special handling.
+      r = Color._clamp((255 + (255 * tintShade)).round().toInt(), 0, 255);
+      g = Color._clamp((255 + (255 * tintShade)).round().toInt(), 0, 255);
+      b = Color._clamp((255 + (255 * tintShade)).round().toInt(), 0, 255);
+    } else {
+      // All other colors then darkening white go here.
+      r = Color._changeTintShadeColor(rgba.r, tintShade).round().toInt();
+      g = Color._changeTintShadeColor(rgba.g, tintShade).round().toInt();
+      b = Color._changeTintShadeColor(rgba.b, tintShade).round().toInt();
+    }
+    return new Rgba(r, g, b, rgba.a);
+  }
+
+  // TODO(terry): This does an okay lighter/darker; better would be convert to
+  //              HSL then change the lightness.
+  /**
+   * The parameter [v] is the color to change (r, g, or b) in the range '0' to
+   * '255'. The parameter [delta] is a number between '-1' and '1'.  A value
+   * between '-1' and '0' is darker and a value between '0' and '1' is lighter
+   * ('0' imples no change).
+   */
+  static num _changeTintShadeColor(num v, num delta) =>
+      Color._clamp(((1 - delta) * v + (delta * 255)).round(), 0, 255);
+
+  // Predefined CSS colors see <http://www.w3.org/TR/css3-color/>
+  static final Color transparent = const Color.hex("00ffffff");  // Alpha 0.0
+  static final Color aliceBlue = const Color.hex("0f08ff");
+  static final Color antiqueWhite = const Color.hex("0faebd7");
+  static final Color aqua = const Color.hex("00ffff");
+  static final Color aquaMarine = const Color.hex("7fffd4");
+  static final Color azure = const Color.hex("f0ffff");
+  static final Color beige = const Color.hex("f5f5dc");
+  static final Color bisque = const Color.hex("ffe4c4");
+  static final Color black = const Color.hex("000000");
+  static final Color blanchedAlmond = const Color.hex("ffebcd");
+  static final Color blue = const Color.hex("0000ff");
+  static final Color blueViolet = const Color.hex("8a2be2");
+  static final Color brown = const Color.hex("a52a2a");
+  static final Color burlyWood = const Color.hex("deb887");
+  static final Color cadetBlue = const Color.hex("5f9ea0");
+  static final Color chartreuse = const Color.hex("7fff00");
+  static final Color chocolate = const Color.hex("d2691e");
+  static final Color coral = const Color.hex("ff7f50");
+  static final Color cornFlowerBlue = const Color.hex("6495ed");
+  static final Color cornSilk = const Color.hex("fff8dc");
+  static final Color crimson = const Color.hex("dc143c");
+  static final Color cyan = const Color.hex("00ffff");
+  static final Color darkBlue = const Color.hex("00008b");
+  static final Color darkCyan = const Color.hex("008b8b");
+  static final Color darkGoldenRod = const Color.hex("b8860b");
+  static final Color darkGray = const Color.hex("a9a9a9");
+  static final Color darkGreen = const Color.hex("006400");
+  static final Color darkGrey = const Color.hex("a9a9a9");
+  static final Color darkKhaki = const Color.hex("bdb76b");
+  static final Color darkMagenta = const Color.hex("8b008b");
+  static final Color darkOliveGreen = const Color.hex("556b2f");
+  static final Color darkOrange = const Color.hex("ff8c00");
+  static final Color darkOrchid = const Color.hex("9932cc");
+  static final Color darkRed = const Color.hex("8b0000");
+  static final Color darkSalmon = const Color.hex("e9967a");
+  static final Color darkSeaGreen = const Color.hex("8fbc8f");
+  static final Color darkSlateBlue = const Color.hex("483d8b");
+  static final Color darkSlateGray = const Color.hex("2f4f4f");
+  static final Color darkSlateGrey = const Color.hex("2f4f4f");
+  static final Color darkTurquoise = const Color.hex("00ced1");
+  static final Color darkViolet = const Color.hex("9400d3");
+  static final Color deepPink = const Color.hex("ff1493");
+  static final Color deepSkyBlue = const Color.hex("00bfff");
+  static final Color dimGray = const Color.hex("696969");
+  static final Color dimGrey = const Color.hex("696969");
+  static final Color dodgerBlue = const Color.hex("1e90ff");
+  static final Color fireBrick = const Color.hex("b22222");
+  static final Color floralWhite = const Color.hex("fffaf0");
+  static final Color forestGreen = const Color.hex("228b22");
+  static final Color fuchsia = const Color.hex("ff00ff");
+  static final Color gainsboro = const Color.hex("dcdcdc");
+  static final Color ghostWhite = const Color.hex("f8f8ff");
+  static final Color gold = const Color.hex("ffd700");
+  static final Color goldenRod = const Color.hex("daa520");
+  static final Color gray = const Color.hex("808080");
+  static final Color green = const Color.hex("008000");
+  static final Color greenYellow = const Color.hex("adff2f");
+  static final Color grey = const Color.hex("808080");
+  static final Color honeydew = const Color.hex("f0fff0");
+  static final Color hotPink = const Color.hex("ff69b4");
+  static final Color indianRed = const Color.hex("cd5c5c");
+  static final Color indigo = const Color.hex("4b0082");
+  static final Color ivory = const Color.hex("fffff0");
+  static final Color khaki = const Color.hex("f0e68c");
+  static final Color lavender = const Color.hex("e6e6fa");
+  static final Color lavenderBlush = const Color.hex("fff0f5");
+  static final Color lawnGreen = const Color.hex("7cfc00");
+  static final Color lemonChiffon = const Color.hex("fffacd");
+  static final Color lightBlue = const Color.hex("add8e6");
+  static final Color lightCoral = const Color.hex("f08080");
+  static final Color lightCyan = const Color.hex("e0ffff");
+  static final Color lightGoldenRodYellow = const Color.hex("fafad2");
+  static final Color lightGray = const Color.hex("d3d3d3");
+  static final Color lightGreen = const Color.hex("90ee90");
+  static final Color lightGrey = const Color.hex("d3d3d3");
+  static final Color lightPink = const Color.hex("ffb6c1");
+  static final Color lightSalmon = const Color.hex("ffa07a");
+  static final Color lightSeaGreen = const Color.hex("20b2aa");
+  static final Color lightSkyBlue = const Color.hex("87cefa");
+  static final Color lightSlateGray = const Color.hex("778899");
+  static final Color lightSlateGrey = const Color.hex("778899");
+  static final Color lightSteelBlue = const Color.hex("b0c4de");
+  static final Color lightYellow = const Color.hex("ffffe0");
+  static final Color lime = const Color.hex("00ff00");
+  static final Color limeGreen = const Color.hex("32cd32");
+  static final Color linen = const Color.hex("faf0e6");
+  static final Color magenta = const Color.hex("ff00ff");
+  static final Color maroon = const Color.hex("800000");
+  static final Color mediumAquaMarine = const Color.hex("66cdaa");
+  static final Color mediumBlue = const Color.hex("0000cd");
+  static final Color mediumOrchid = const Color.hex("ba55d3");
+  static final Color mediumPurple = const Color.hex("9370db");
+  static final Color mediumSeaGreen = const Color.hex("3cb371");
+  static final Color mediumSlateBlue = const Color.hex("7b68ee");
+  static final Color mediumSpringGreen = const Color.hex("00fa9a");
+  static final Color mediumTurquoise = const Color.hex("48d1cc");
+  static final Color mediumVioletRed = const Color.hex("c71585");
+  static final Color midnightBlue = const Color.hex("191970");
+  static final Color mintCream = const Color.hex("f5fffa");
+  static final Color mistyRose = const Color.hex("ffe4e1");
+  static final Color moccasin = const Color.hex("ffe4b5");
+  static final Color navajoWhite = const Color.hex("ffdead");
+  static final Color navy = const Color.hex("000080");
+  static final Color oldLace = const Color.hex("fdf5e6");
+  static final Color olive = const Color.hex("808000");
+  static final Color oliveDrab = const Color.hex("6b8e23");
+  static final Color orange = const Color.hex("ffa500");
+  static final Color orangeRed = const Color.hex("ff4500");
+  static final Color orchid = const Color.hex("da70d6");
+  static final Color paleGoldenRod = const Color.hex("eee8aa");
+  static final Color paleGreen = const Color.hex("98fb98");
+  static final Color paleTurquoise = const Color.hex("afeeee");
+  static final Color paleVioletRed = const Color.hex("db7093");
+  static final Color papayaWhip = const Color.hex("ffefd5");
+  static final Color peachPuff = const Color.hex("ffdab9");
+  static final Color peru = const Color.hex("cd85ef");
+  static final Color pink = const Color.hex("ffc0cb");
+  static final Color plum = const Color.hex("dda0dd");
+  static final Color powderBlue = const Color.hex("b0e0e6");
+  static final Color purple = const Color.hex("800080");
+  static final Color red = const Color.hex("ff0000");
+  static final Color rosyBrown = const Color.hex("bc8f8f");
+  static final Color royalBlue = const Color.hex("4169e1");
+  static final Color saddleBrown = const Color.hex("8b4513");
+  static final Color salmon = const Color.hex("fa8072");
+  static final Color sandyBrown = const Color.hex("f4a460");
+  static final Color seaGreen = const Color.hex("2e8b57");
+  static final Color seashell = const Color.hex("fff5ee");
+  static final Color sienna = const Color.hex("a0522d");
+  static final Color silver = const Color.hex("c0c0c0");
+  static final Color skyBlue = const Color.hex("87ceeb");
+  static final Color slateBlue = const Color.hex("6a5acd");
+  static final Color slateGray = const Color.hex("708090");
+  static final Color slateGrey = const Color.hex("708090");
+  static final Color snow = const Color.hex("fffafa");
+  static final Color springGreen = const Color.hex("00ff7f");
+  static final Color steelBlue = const Color.hex("4682b4");
+  static final Color tan = const Color.hex("d2b48c");
+  static final Color teal = const Color.hex("008080");
+  static final Color thistle = const Color.hex("d8bfd8");
+  static final Color tomato = const Color.hex("ff6347");
+  static final Color turquoise = const Color.hex("40e0d0");
+  static final Color violet = const Color.hex("ee82ee");
+  static final Color wheat = const Color.hex("f5deb3");
+  static final Color white = const Color.hex("ffffff");
+  static final Color whiteSmoke = const Color.hex("f5f5f5");
+  static final Color yellow = const Color.hex("ffff00");
+  static final Color yellowGreen = const Color.hex("9acd32");
+}
+
+
+/**
+ * Rgba class for users that want to interact with a color as a RGBA value.
+ */
+class Rgba implements _StyleProperty, ColorBase {
+  // TODO(terry): Consider consolidating rgba to a single 32-bit int, make sure
+  //              it works under JS and Dart VM.
+  final int r;
+  final int g;
+  final int b;
+  final num a;
+
+  Rgba(int red, int green, int blue, [num alpha]) :
+    this.r = Color._clamp(red, 0, 255),
+    this.g = Color._clamp(green, 0, 255),
+    this.b = Color._clamp(blue, 0, 255),
+    this.a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha;
+
+  factory Rgba.fromString(String hexValue) =>
+    new Color.css("#${Color._convertCssToArgb(hexValue)}").rgba;
+
+  factory Rgba.fromColor(Color color) => color.rgba;
+
+  factory Rgba.fromArgbValue(num value) {
+    return new Rgba(((value.toInt() & 0xff000000) >> 0x18),  /* a */
+      ((value.toInt() & 0xff0000) >> 0x10),                  /* r */
+      ((value.toInt() & 0xff00) >> 8),                       /* g */
+      ((value.toInt() & 0xff)));                             /* b */
+  }
+
+  factory Rgba.fromHsla(Hsla hsla) {
+    // Convert to Rgba.
+    // See site <http://easyrgb.com/index.php?X=MATH> for good documentation
+    // and color conversion routines.
+
+    num h = hsla.hue;
+    num s = hsla.saturation;
+    num l = hsla.lightness;
+    num a = hsla.alpha;
+
+    int r;
+    int g;
+    int b;
+
+    if (s == 0) {
+      r = (l * 255).round().toInt();
+      g = r;
+      b = r;
+    } else {
+      num var2;
+
+      if (l < 0.5) {
+        var2 = l * (1 + s);
+      } else {
+        var2 = (l + s) - (s * l);
+      }
+      num var1 = 2 * l - var2;
+
+      r = (255 * Rgba._hueToRGB(var1, var2, h + (1/3))).round().toInt();
+      g = (255 * Rgba._hueToRGB(var1, var2, h)).round().toInt();
+      b = (255 * Rgba._hueToRGB(var1, var2, h - (1/3))).round().toInt();
+    }
+
+    return new Rgba(r, g, b, a);
+  }
+
+  static num _hueToRGB(num v1, num v2, num vH) {
+    if (vH < 0) {
+      vH += 1;
+    }
+
+    if (vH > 1) {
+      vH -= 1;
+    }
+
+    if ((6 * vH) < 1) {
+      return (v1 + (v2 - v1) * 6 * vH);
+    }
+
+    if ((2 * vH) < 1) {
+      return v2;
+    }
+
+    if ((3 * vH) < 2) {
+      return (v1 + (v2 - v1) * ((2 / 3 - vH) * 6));
+    }
+
+    return v1;
+  }
+
+  bool operator ==(Object other) => Color.equal(this, other);
+
+  String get cssExpression {
+    if (a == null) {
+      return "#${Color.convertToHexString(r, g, b)}";
+    } else {
+      return "rgba($r,$g,$b,$a)";
+    }
+  }
+
+  String toHexArgbString() => Color.convertToHexString(r, g, b, a);
+
+  int get argbValue {
+    int value = 0;
+    if (a != null) {
+      value = (a.toInt() << 0x18);
+    }
+    value += (r << 0x10);
+    value += (g << 0x08);
+    value += b;
+  }
+
+  Color get color => new Color.createRgba(r, g, b, a);
+  Hsla get hsla => new Hsla.fromRgba(this);
+
+  Rgba darker(num amount) => Color._createNewTintShadeFromRgba(this, -amount);
+  Rgba lighter(num amount) => Color._createNewTintShadeFromRgba(this, amount);
+
+  int get hashCode => toHexArgbString().hashCode;
+}
+
+
+/**
+ * Hsl class support to interact with a color as a hsl with hue, saturation, and
+ * lightness with optional alpha blending.  The hue is a ratio of 360 degrees
+ * 360° = 1 or 0, (1° == (1/360)), saturation and lightness is a 0..1 fraction
+ * (1 == 100%) and alpha is a 0..1 fraction.
+ */
+class Hsla implements _StyleProperty, ColorBase {
+  final num _h;             // Value from 0..1
+  final num _s;             // Value from 0..1
+  final num _l;             // Value from 0..1
+  final num _a;             // Value from 0..1
+
+  /**
+   * [hue] is a 0..1 fraction of 360 degrees (360 == 0).
+   * [saturation] is a 0..1 fraction (100% == 1).
+   * [lightness] is a 0..1 fraction (100% == 1).
+   * [alpha] is a 0..1 fraction, alpha blending between 0..1, 1 == 100% opaque.
+   */
+  Hsla(num hue, num saturation, num lightness, [num alpha]) :
+    this._h = (hue == 1) ? 0 : Color._clamp(hue, 0, 1),
+    this._s = Color._clamp(saturation, 0, 1),
+    this._l = Color._clamp(lightness, 0, 1),
+    this._a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha;
+
+  factory Hsla.fromString(String hexValue) {
+    Rgba rgba = new Color.css("#${Color._convertCssToArgb(hexValue)}").rgba;
+    return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a);
+  }
+
+  factory Hsla.fromColor(Color color) {
+    Rgba rgba = color.rgba;
+    return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a);
+  }
+
+  factory Hsla.fromArgbValue(num value) {
+    num a = (value.toInt() & 0xff000000) >> 0x18;
+    int r = (value.toInt() & 0xff0000) >> 0x10;
+    int g = (value.toInt() & 0xff00) >> 8;
+    int b = value.toInt() & 0xff;
+
+    // Convert alpha to 0..1 from (0..255).
+    if (a != null) {
+      a = double.parse((a / 255).toStringAsPrecision(2));
+    }
+
+    return _createFromRgba(r, g, b, a);
+  }
+
+  factory Hsla.fromRgba(Rgba rgba) =>
+    _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a);
+
+  static Hsla _createFromRgba(num r, num g, num b, num a) {
+    // Convert RGB to hsl.
+    // See site <http://easyrgb.com/index.php?X=MATH> for good documentation
+    // and color conversion routines.
+    r /= 255;
+    g /= 255;
+    b /= 255;
+
+    // Hue, saturation and lightness.
+    num h;
+    num s;
+    num l;
+
+    num minRgb = math.min(r, math.min(g, b));
+    num maxRgb = math.max(r, math.max(g, b));
+    l = (maxRgb + minRgb) / 2;
+    if (l <= 0) {
+      return new Hsla(0, 0, l);   // Black;
+    }
+
+    num vm = maxRgb - minRgb;
+    s = vm;
+    if (s > 0) {
+      s /= (l < 0.5) ? (maxRgb + minRgb) : (2 - maxRgb - minRgb);
+    } else {
+      return new Hsla(0, 0, l);   // White
+    }
+
+    num r2, g2, b2;
+    r2 = (maxRgb - r) / vm;
+    g2 = (maxRgb - g) / vm;
+    b2 = (maxRgb - b) / vm;
+    if (r == maxRgb) {
+      h = (g == minRgb) ? 5.0 + b2 : 1 - g2;
+    } else if (g == maxRgb) {
+      h = (b == minRgb) ? 1 + r2 : 3 - b2;
+    } else {
+      h = (r == minRgb) ? 3 + g2 : 5 - r2;
+    }
+    h /= 6;
+
+    return new Hsla(h, s, l, a);
+  }
+
+  /**
+   * Returns 0..1 fraction (ratio of 360°, e.g. 1° == 1/360).
+   */
+  num get hue => _h;
+
+  /**
+   * Returns 0..1 fraction (1 == 100%)
+   */
+  num get saturation => _s;
+
+  /**
+   * Returns 0..1 fraction (1 == 100%).
+   */
+  num get lightness => _l;
+
+  /**
+   * Returns number as degrees 0..360.
+   */
+  num get hueDegrees => (_h * 360).round();
+
+  /**
+   * Returns number as percentage 0..100
+   */
+  num get saturationPercentage => (_s * 100).round();
+
+  /**
+   * Returns number as percentage 0..100.
+   */
+  num get lightnessPercentage => (_l * 100).round();
+
+  /**
+   * Returns number as 0..1
+   */
+  num get alpha => _a;
+
+  bool operator ==(Object other) => Color.equal(this, other);
+
+  String get cssExpression => (_a == null) ?
+      "hsl($hueDegrees,$saturationPercentage,$lightnessPercentage)" :
+      "hsla($hueDegrees,$saturationPercentage,$lightnessPercentage,$_a)";
+
+  String toHexArgbString() => new Rgba.fromHsla(this).toHexArgbString();
+
+  int get argbValue => Color.hexToInt(this.toHexArgbString());
+
+  Color get color => new Color.createHsla(_h, _s, _l, _a);
+  Rgba get rgba => new Rgba.fromHsla(this);
+
+  Hsla darker(num amount) =>
+      new Hsla.fromRgba(new Rgba.fromHsla(this).darker(amount));
+
+  Hsla lighter(num amount) =>
+      new Hsla.fromRgba(new Rgba.fromHsla(this).lighter(amount));
+
+  int get hashCode => toHexArgbString().hashCode;
+}
+
+
+/** X,Y position. */
+class PointXY implements _StyleProperty {
+  final num x, y;
+  const PointXY(this.x, this.y);
+
+  String get cssExpression {
+    // TODO(terry): TBD
+  }
+}
+
+
+// TODO(terry): Implement style and color.
+/**
+ * Supports border for measuring with layout.
+ */
+class Border implements _StyleProperty {
+  final int top, left, bottom, right;
+
+  // TODO(terry): Just like CSS, 1-arg -> set all properties, 2-args -> top and
+  //               bottom are first arg, left and right are second, 3-args, and
+  //               4-args -> tlbr or trbl.
+  const Border([this.top, this.left, this.bottom, this.right]);
+
+  // TODO(terry): Consider using Size or width and height.
+  Border.uniform(num amount) :
+      top = amount, left = amount, bottom = amount, right = amount;
+
+  int get width => left + right;
+  int get height => top + bottom;
+
+  String get cssExpression {
+    return (top == left && bottom == right && top == right) ? "${left}px" :
+      "${top != null ? '$top' : '0'}px ${
+      right != null ? '$right' : '0'}px ${
+      bottom != null ? '$bottom' : '0'}px ${
+      left != null ? '$left' : '0'}px";
+  }
+}
+
+
+/** Font style constants. */
+class FontStyle {
+  /** Font style [normal] default. */
+  static const String normal = "normal";
+  /**
+   * Font style [italic] use explicity crafted italic font otherwise inclined
+   * on the fly like oblique.
+   */
+  static const String italic = "italic";
+  /**
+   * Font style [oblique] is rarely used. The normal style of a font is inclined
+   * on the fly to the right by 8-12 degrees.
+   */
+  static const String oblique = "oblique";
+}
+
+
+/** Font variant constants. */
+class FontVariant {
+  /** Font style [normal] default. */
+  static const String normal = "normal";
+  /** Font variant [smallCaps]. */
+  static const String smallCaps = "small-caps";
+}
+
+
+/** Font weight constants values 100, 200, 300, 400, 500, 600, 700, 800, 900. */
+class FontWeight {
+  /** Font weight normal [default] */
+  static const int normal = 400;
+  /** Font weight bold */
+  static const int bold = 700;
+
+  static const int wt100 = 100;
+  static const int wt200 = 200;
+  static const int wt300 = 300;
+  static const int wt400 = 400;
+  static const int wt500 = 500;
+  static const int wt600 = 600;
+  static const int wt700 = 700;
+  static const int wt800 = 800;
+  static const int wt900 = 900;
+}
+
+
+/** Generic font family names. */
+class FontGeneric {
+  /** Generic family sans-serif font (w/o serifs). */
+  static const String sansSerif = "sans-serif";
+  /** Generic family serif font. */
+  static const String serif = "serif";
+  /** Generic family fixed-width font. */
+  static const monospace = "monospace";
+  /** Generic family emulate handwriting font. */
+  static const String cursive = "cursive";
+  /** Generic family decorative font. */
+  static const String fantasy = "fantasy";
+}
+
+
+/**
+ * List of most common font families across different platforms.  Use the
+ * collection names in the Font class (e.g., Font.SANS_SERIF, Font.FONT_SERIF,
+ * Font.MONOSPACE, Font.CURSIVE or Font.FANTASY).  These work best on all
+ * platforms using the fonts that best match availability on each platform.
+ * See <http://www.angelfire.com/al4/rcollins/style/fonts.html> for a good
+ * description of fonts available between platforms and browsers.
+ */
+class FontFamily {
+  /** Sans-Serif font for Windows similar to Helvetica on Mac bold/italic. */
+  static const String arial = "arial";
+  /** Sans-Serif font for Windows less common already bolded. */
+  static const String arialBlack = "arial black";
+  /** Sans-Serif font for Mac since 1984, similar to Arial/Helvetica. */
+  static const String geneva = "geneva";
+  /** Sans-Serif font for Windows most readable sans-serif font for displays. */
+  static const String verdana = "verdana";
+  /** Sans-Serif font for Mac since 1984 is identical to Arial. */
+  static const String helvetica = "helvetica";
+
+  /** Serif font for Windows traditional font with “old-style” numerals. */
+  static const String georgia = "georgia";
+  /**
+   * Serif font for Mac. PCs may have the non-scalable Times use Times New
+   * Roman instead.  Times is more compact than Times New Roman.
+   */
+  static const String times = "times";
+  /**
+   * Serif font for Windows most common serif font and default serif font for
+   * most browsers.
+   */
+  static const String timesNewRoman = "times new roman";
+
+  /**
+   * Monospace font for Mac/Windows most common. Scalable on Mac not scalable
+   * on Windows.
+   */
+  static const String courier = "courier";
+  /** Monospace font for Mac/Windows scalable on both platforms. */
+  static const String courierNew = "courier new";
+
+  /** Cursive font for Windows and default cursive font for IE. */
+  static const String comicSansMs = "comic sans ms";
+  /** Cursive font for Mac on Macs 2000 and newer. */
+  static const String textile = "textile";
+  /** Cursive font for older Macs. */
+  static const String appleChancery = "apple chancery";
+  /** Cursive font for some PCs. */
+  static const String zaphChancery = "zaph chancery";
+
+  /** Fantasy font on most Mac/Windows/Linux platforms. */
+  static const String impact = "impact";
+  /** Fantasy font for Windows. */
+  static const String webdings = "webdings";
+}
+
+class LineHeight {
+  final num height;
+  final bool inPixels;
+  const LineHeight(this.height, {this.inPixels : true});
+}
+
+// TODO(terry): Support @font-face fule.
+/**
+ * Font style support for size, family, weight, style, variant, and lineheight.
+ */
+class Font implements _StyleProperty {
+  /** Collection of most common sans-serif fonts in order. */
+  static const List<String> sansSerif = const [FontFamily.arial,
+                                               FontFamily.verdana,
+                                               FontFamily.geneva,
+                                               FontFamily.helvetica,
+                                               FontGeneric.sansSerif];
+
+  /** Collection of most common serif fonts in order. */
+  static const List<String> serif = const [FontFamily.georgia,
+                                           FontFamily.timesNewRoman,
+                                           FontFamily.times,
+                                           FontGeneric.serif];
+  /** Collection of most common monospace fonts in order. */
+  static const List<String> monospace = const [FontFamily.courierNew,
+                                               FontFamily.courier,
+                                               FontGeneric.monospace];
+  /** Collection of most common cursive fonts in order. */
+  static const List<String> cursive = const [FontFamily.textile,
+                                             FontFamily.appleChancery,
+                                             FontFamily.zaphChancery,
+                                             FontGeneric.fantasy];
+  /** Collection of most common fantasy fonts in order. */
+  static const List<String> fantasy = const [FontFamily.comicSansMs,
+                                             FontFamily.impact,
+                                             FontFamily.webdings,
+                                             FontGeneric.fantasy];
+
+  // TODO(terry): Should support the values xx-small, small, large, xx-large,
+  //              etc. (mapped to a pixel sized font)?
+  /** Font size in pixels. */
+  final num size;
+
+  // TODO(terry): _family should be an immutable list, wrapper class to do this
+  //              should exist in Dart.
+  /**
+   * Family specifies a list of fonts, the browser will sequentially select the
+   * the first known/supported font.  There are two types of font families the
+   * family-name (e.g., arial, times, courier, etc) or the generic-family (e.g.,
+   * serif, sans-seric, etc.)
+   */
+  final List<String> family;
+
+  /** Font weight from 100, 200, 300, 400, 500, 600, 700, 800, 900 */
+  final int weight;
+
+  /** Style of a font normal, italic, oblique. */
+  final String style;
+
+  /**
+   * Font variant NORMAL (default) or SMALL_CAPS.  Different set of font glyph
+   * lower case letters designed to have to fit within the font-height and
+   * weight of the corresponding lowercase letters.
+   */
+  final String variant;
+
+  final LineHeight lineHeight;
+
+  // TODO(terry): Size and computedLineHeight are in pixels.  Need to figure out
+  //              how to handle in other units (specified in other units) like
+  //              points, inches, etc.  Do we have helpers like Units.Points(12)
+  //              where 12 is in points and that's converted to pixels?
+  // TODO(terry): lineHeight is computed as 1.2 although CSS_RESET is 1.0 we
+  //              need to be consistent some browsers use 1 others 1.2.
+  // TODO(terry): There is a school of thought "Golden Ratio Typography".
+  // Where width to display the text is also important in computing the line
+  // height.  Classic typography suggest the ratio be 1.5.  See
+  // <http://www.pearsonified.com/2011/12/golden-ratio-typography.php> and
+  // <http://meyerweb.com/eric/thoughts/2008/05/06/line-height-abnormal/>.
+  /**
+   * Create a font using [size] of font in pixels, [family] name of font(s)
+   * using [FontFamily], [style] of the font using [FontStyle], [variant] using
+   * [FontVariant], and [lineHeight] extra space (leading) around the font in
+   * pixels, if not specified it's 1.2 the font size.
+   */
+  const Font({this.size, this.family, this.weight, this.style, this.variant,
+              this.lineHeight});
+
+  /**
+   * Merge the two fonts and return the result. See [Style.merge] for
+   * more information.
+   */
+  factory Font.merge(Font a, Font b) {
+    if (a == null) return b;
+    if (b == null) return a;
+    return new Font._merge(a, b);
+  }
+
+  Font._merge(Font a, Font b)
+    : size = _mergeVal(a.size, b.size),
+      family = _mergeVal(a.family, b.family),
+      weight = _mergeVal(a.weight, b.weight),
+      style = _mergeVal(a.style, b.style),
+      variant = _mergeVal(a.variant, b.variant),
+      lineHeight = _mergeVal(a.lineHeight, b.lineHeight);
+
+  /**
+   * Shorthand CSS format for font is:
+   *
+   *    font-style font-variant font-weight font-size/line-height font-family
+   *
+   * The font-size and font-family values are required. If any of the other
+   * values are missing the default value is used.
+   */
+  String get cssExpression {
+    // TODO(jimhug): include variant, style, other options
+    if (weight != null) {
+      // TODO(jacobr): is this really correct for lineHeight?
+      if (lineHeight != null) {
+        return "$weight ${size}px/$lineHeightInPixels $_fontsAsString";
+      }
+      return '$weight ${size}px $_fontsAsString';
+    }
+
+    return '${size}px $_fontsAsString';
+  }
+
+  Font scale(num ratio) =>
+      new Font(size: size * ratio, family: family, weight: weight, style: style,
+          variant: variant);
+
+  /**
+   * The lineHeight, provides an indirect means to specify the leading. The
+   * leading is the difference between the font-size height and the (used)
+   * value of line height in pixels.  If lineHeight is not specified it's
+   * automatically computed as 1.2 of the font size.  Firefox is 1.2, Safari is
+   * ~1.2, and CSS suggest a ration from 1 to 1.2 of the font-size when
+   * computing line-height. The Font class constructor has the computation for
+   * _lineHeight.
+   */
+  num get lineHeightInPixels {
+    if (lineHeight != null) {
+      if (lineHeight.inPixels) {
+        return lineHeight.height;
+      } else {
+        return (size != null) ? lineHeight.height * size : null;
+      }
+    } else {
+      return (size != null) ? size * 1.2 : null;
+    }
+  }
+
+  int get hashCode {
+    // TODO(jimhug): Lot's of potential collisions here. List of fonts, etc.
+    return size.toInt() % family[0].hashCode;
+  }
+
+  bool operator ==(Object other) {
+    if (other is! Font) return false;
+    Font o = other;
+    return o.size == size && o.family == family && o.weight == weight &&
+        o.lineHeight == lineHeight && o.style == style && o.variant == variant;
+  }
+
+  // TODO(terry): This is fragile should probably just iterate through the list
+  //              of fonts construction the font-family string.
+  /** Return fonts as a comma seperated list sans the square brackets. */
+  String get _fontsAsString {
+    String fonts = family.toString();
+    return fonts.length > 2 ? fonts.substring(1, fonts.length - 1) : "";
+  }
+}
+
+/**
+ * This class stores the sizes of the box edges in the CSS [box model][]. Each
+ * edge area is placed around the sides of the content box. The innermost area
+ * is the [Style.padding] area which has a background and surrounds the content.
+ * The content and padding area is surrounded by the [Style.border], which
+ * itself is surrounded by the transparent [Style.margin]. This box represents
+ * the eges of padding, border, or margin depending on which accessor was used
+ * to retrieve it.
+ *
+ * [box model]: https://developer.mozilla.org/en/CSS/box_model
+ */
+class BoxEdge {
+  /** The size of the left edge, or null if the style has no edge. */
+  final num left;
+
+  /** The size of the top edge, or null if the style has no edge. */
+  final num top;
+
+  /** The size of the right edge, or null if the style has no edge. */
+  final num right;
+
+  /** The size of the bottom edge, or null if the style has no edge. */
+  final num bottom;
+
+  /**
+   * Creates a box edge with the specified [left], [top], [right], and
+   * [bottom] width.
+   */
+  const BoxEdge([this.left, this.top, this.right, this.bottom]);
+
+  /**
+   * Creates a box edge with the specified [top], [right], [bottom], and
+   * [left] width. This matches the typical CSS order:
+   * <https://developer.mozilla.org/en/CSS/margin>
+   * <https://developer.mozilla.org/en/CSS/border-width>
+   * <https://developer.mozilla.org/en/CSS/padding>.
+   */
+   const BoxEdge.clockwiseFromTop(this.top, this.right, this.bottom, this.left);
+
+  /**
+   * This is a helper to creates a box edge with the same [left], [top]
+   * [right], and [bottom] widths.
+   */
+  const BoxEdge.uniform(num size)
+    : top = size, left = size, bottom = size, right = size;
+
+  /**
+   * Takes a possibly null box edge, with possibly null metrics, and fills
+   * them in with 0 instead.
+   */
+  factory BoxEdge.nonNull(BoxEdge other) {
+    if (other == null) return const BoxEdge(0, 0, 0, 0);
+    num left = other.left;
+    num top = other.top;
+    num right = other.right;
+    num bottom = other.bottom;
+    bool make = false;
+    if (left == null) {
+      make = true;
+      left = 0;
+    }
+    if (top == null) {
+      make = true;
+      top = 0;
+    }
+    if (right == null) {
+      make = true;
+      right = 0;
+    }
+    if (bottom == null) {
+      make = true;
+      bottom = 0;
+    }
+    return make ? new BoxEdge(left, top, right, bottom) : other;
+  }
+
+  /**
+   * Merge the two box edge sizes and return the result. See [Style.merge] for
+   * more information.
+   */
+  factory BoxEdge.merge(BoxEdge x, BoxEdge y) {
+    if (x == null) return y;
+    if (y == null) return x;
+    return new BoxEdge._merge(x, y);
+  }
+
+  BoxEdge._merge(BoxEdge x, BoxEdge y)
+    : left = _mergeVal(x.left, y.left),
+      top = _mergeVal(x.top, y.top),
+      right = _mergeVal(x.right, y.right),
+      bottom = _mergeVal(x.bottom, y.bottom);
+
+  /**
+   * The total size of the horizontal edges. Equal to [left] + [right], where
+   * null is interpreted as 0px.
+   */
+  num get width => (left != null ? left : 0) + (right != null ? right : 0);
+
+  /**
+   * The total size of the vertical edges. Equal to [top] + [bottom], where
+   * null is interpreted as 0px.
+   */
+  num get height => (top != null ? top : 0) + (bottom != null ? bottom : 0);
+}
+
+_mergeVal(x, y) => y != null ? y : x;
diff --git a/pkg/csslib/lib/src/token.dart b/pkg/csslib/lib/src/token.dart
new file mode 100644
index 0000000..cf9e376
--- /dev/null
+++ b/pkg/csslib/lib/src/token.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.parser;
+
+/**
+ * A single token in the Dart language.
+ */
+class Token {
+  /** A member of [TokenKind] specifying what kind of token this is. */
+  final int kind;
+
+  /** The location where this token was parsed from. */
+  final Span span;
+
+  /** The start offset of this token. */
+  int get start => span.start.offset;
+
+  /** The end offset of this token. */
+  int get end => span.end.offset;
+
+  /** Returns the source text corresponding to this [Token]. */
+  String get text => span.text;
+
+  Token(this.kind, this.span);
+
+  /** Returns a pretty representation of this token for error messages. **/
+  String toString() {
+    var kindText = TokenKind.kindToString(kind);
+    var actualText = text;
+    if (kindText != actualText) {
+      if (actualText.length > 10) {
+        actualText = '${actualText.substring(0, 8)}...';
+      }
+      return '$kindText($actualText)';
+    } else {
+      return kindText;
+    }
+  }
+}
+
+/** A token containing a parsed literal value. */
+class LiteralToken extends Token {
+  var value;
+  LiteralToken(int kind, Span span, this.value) : super(kind, span);
+}
+
+/** A token containing error information. */
+class ErrorToken extends Token {
+  String message;
+  ErrorToken(int kind, Span span, this.message) : super(kind, span);
+}
diff --git a/pkg/csslib/lib/src/tokenizer.dart b/pkg/csslib/lib/src/tokenizer.dart
new file mode 100644
index 0000000..e3cdfdc
--- /dev/null
+++ b/pkg/csslib/lib/src/tokenizer.dart
@@ -0,0 +1,409 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.parser;
+
+class Tokenizer extends TokenizerBase {
+  /** U+ prefix for unicode characters. */
+  final UNICODE_U = 'U'.codeUnitAt(0);
+  final UNICODE_LOWER_U = 'u'.codeUnitAt(0);
+  final UNICODE_PLUS = '+'.codeUnitAt(0);
+
+  final QUESTION_MARK = '?'.codeUnitAt(0);
+
+  /** CDATA keyword. */
+  final List CDATA_NAME = 'CDATA'.codeUnits;
+
+  Tokenizer(SourceFile file, String text, bool skipWhitespace,
+      [int index = 0])
+      : super(file, text, skipWhitespace, index);
+
+  Token next({unicodeRange: false}) {
+    // keep track of our starting position
+    _startIndex = _index;
+
+    int ch;
+    ch = _nextChar();
+    switch (ch) {
+      case TokenChar.NEWLINE:
+      case TokenChar.RETURN:
+      case TokenChar.SPACE:
+      case TokenChar.TAB:
+        return finishWhitespace();
+      case TokenChar.END_OF_FILE:
+        return _finishToken(TokenKind.END_OF_FILE);
+      case TokenChar.AT:
+        int peekCh = _peekChar();
+        if (TokenizerHelpers.isIdentifierStart(peekCh)) {
+          var oldIndex = _index;
+          var oldStartIndex = _startIndex;
+
+          _startIndex = _index;
+          ch = _nextChar();
+          Token ident = this.finishIdentifier(ch);
+
+          // Is it a directive?
+          int tokId = TokenKind.matchDirectives(_text, _startIndex,
+              _index - _startIndex);
+          if (tokId == -1) {
+            // No, is it a margin directive?
+            tokId = TokenKind.matchMarginDirectives(_text, _startIndex,
+                _index - _startIndex);
+          }
+
+          if (tokId != -1) {
+            return _finishToken(tokId);
+          } else {
+            // Didn't find a CSS directive or margin directive so the @name is
+            // probably the Less definition '@name: value_variable_definition'.
+            _startIndex = oldStartIndex;
+            _index = oldIndex;
+          }
+        }
+        return _finishToken(TokenKind.AT);
+      case TokenChar.DOT:
+        int start = _startIndex;             // Start where the dot started.
+        if (maybeEatDigit()) {
+          // looks like a number dot followed by digit(s).
+          Token number = finishNumber();
+          if (number.kind == TokenKind.INTEGER) {
+            // It's a number but it's preceeded by a dot, so make it a double.
+            _startIndex = start;
+            return _finishToken(TokenKind.DOUBLE);
+          } else {
+            // Don't allow dot followed by a double (e.g,  '..1').
+            return _errorToken();
+          }
+        }
+        // It's really a dot.
+        return _finishToken(TokenKind.DOT);
+      case TokenChar.LPAREN:
+        return _finishToken(TokenKind.LPAREN);
+      case TokenChar.RPAREN:
+        return _finishToken(TokenKind.RPAREN);
+      case TokenChar.LBRACE:
+        return _finishToken(TokenKind.LBRACE);
+      case TokenChar.RBRACE:
+        return _finishToken(TokenKind.RBRACE);
+      case TokenChar.LBRACK:
+        return _finishToken(TokenKind.LBRACK);
+      case TokenChar.RBRACK:
+        if (_maybeEatChar(TokenChar.RBRACK) &&
+            _maybeEatChar(TokenChar.GREATER)) {
+          // ]]>
+          return next();
+        }
+        return _finishToken(TokenKind.RBRACK);
+      case TokenChar.HASH:
+        return _finishToken(TokenKind.HASH);
+      case TokenChar.PLUS:
+        if (maybeEatDigit()) return finishNumber();
+        return _finishToken(TokenKind.PLUS);
+      case TokenChar.MINUS:
+        if (selectorExpression || unicodeRange) {
+          // If parsing in pseudo function expression then minus is an operator
+          // not part of identifier e.g., interval value range (e.g. U+400-4ff)
+          // or minus operator in selector expression.
+          return _finishToken(TokenKind.MINUS);
+        } else if (maybeEatDigit()) {
+          return finishNumber();
+        } else if (TokenizerHelpers.isIdentifierStart(ch)) {
+          return this.finishIdentifier(ch);
+        }
+        return _finishToken(TokenKind.MINUS);
+      case TokenChar.GREATER:
+        return _finishToken(TokenKind.GREATER);
+      case TokenChar.TILDE:
+        if (_maybeEatChar(TokenChar.EQUALS)) {
+          return _finishToken(TokenKind.INCLUDES);          // ~=
+        }
+        return _finishToken(TokenKind.TILDE);
+      case TokenChar.ASTERISK:
+        if (_maybeEatChar(TokenChar.EQUALS)) {
+          return _finishToken(TokenKind.SUBSTRING_MATCH);   // *=
+        }
+        return _finishToken(TokenKind.ASTERISK);
+      case TokenChar.AMPERSAND:
+        return _finishToken(TokenKind.AMPERSAND);
+      case TokenChar.NAMESPACE:
+        return _finishToken(TokenKind.NAMESPACE);
+      case TokenChar.COLON:
+        return _finishToken(TokenKind.COLON);
+      case TokenChar.COMMA:
+        return _finishToken(TokenKind.COMMA);
+      case TokenChar.SEMICOLON:
+        return _finishToken(TokenKind.SEMICOLON);
+      case TokenChar.PERCENT:
+        return _finishToken(TokenKind.PERCENT);
+      case TokenChar.SINGLE_QUOTE:
+        return _finishToken(TokenKind.SINGLE_QUOTE);
+      case TokenChar.DOUBLE_QUOTE:
+        return _finishToken(TokenKind.DOUBLE_QUOTE);
+      case TokenChar.SLASH:
+        if (_maybeEatChar(TokenChar.ASTERISK)) return finishMultiLineComment();
+        return _finishToken(TokenKind.SLASH);
+      case  TokenChar.LESS:      // <!--
+        if (_maybeEatChar(TokenChar.BANG)) {
+          if (_maybeEatChar(TokenChar.MINUS) &&
+              _maybeEatChar(TokenChar.MINUS)) {
+            return finishMultiLineComment();
+          } else if (_maybeEatChar(TokenChar.LBRACK) &&
+              _maybeEatChar(CDATA_NAME[0]) &&
+              _maybeEatChar(CDATA_NAME[1]) &&
+              _maybeEatChar(CDATA_NAME[2]) &&
+              _maybeEatChar(CDATA_NAME[3]) &&
+              _maybeEatChar(CDATA_NAME[4]) &&
+              _maybeEatChar(TokenChar.LBRACK)) {
+            // <![CDATA[
+            return next();
+          }
+        }
+        return _finishToken(TokenKind.LESS);
+      case TokenChar.EQUALS:
+        return _finishToken(TokenKind.EQUALS);
+      case TokenChar.OR:
+        if (_maybeEatChar(TokenChar.EQUALS)) {
+          return _finishToken(TokenKind.DASH_MATCH);      // |=
+        }
+        return _finishToken(TokenKind.OR);
+      case TokenChar.CARET:
+        if (_maybeEatChar(TokenChar.EQUALS)) {
+          return _finishToken(TokenKind.PREFIX_MATCH);    // ^=
+        }
+        return _finishToken(TokenKind.CARET);
+      case TokenChar.DOLLAR:
+        if (_maybeEatChar(TokenChar.EQUALS)) {
+          return _finishToken(TokenKind.SUFFIX_MATCH);    // $=
+        }
+        return _finishToken(TokenKind.DOLLAR);
+      case TokenChar.BANG:
+        Token tok = finishIdentifier(ch);
+        return (tok == null) ? _finishToken(TokenKind.BANG) : tok;
+      case TokenChar.BACKSLASH:
+        return _finishToken(TokenKind.BACKSLASH);
+      default:
+        if (unicodeRange) {
+          // Three types of unicode ranges:
+          //   - single code point (e.g. U+416)
+          //   - interval value range (e.g. U+400-4ff)
+          //   - range where trailing ‘?’ characters imply ‘any digit value’
+          //   (e.g. U+4??)
+          if (maybeEatHexDigit()) {
+            var t = finishHexNumber();
+            // Any question marks then it's a HEX_RANGE not HEX_NUMBER.
+            if (maybeEatQuestionMark()) finishUnicodeRange();
+            return t;
+          } else if (maybeEatQuestionMark()) {
+            // HEX_RANGE U+N???
+            return finishUnicodeRange();
+          } else {
+            return _errorToken();
+          }
+        } else if ((ch == UNICODE_U || ch == UNICODE_LOWER_U) &&
+            (_peekChar() == UNICODE_PLUS)) {
+          // Unicode range: U+uNumber[-U+uNumber]
+          //   uNumber = 0..10FFFF
+          _nextChar();                                // Skip +
+          _startIndex = _index;                       // Starts at the number
+          return _finishToken(TokenKind.UNICODE_RANGE);
+        } else if (varDef(ch)) {
+          return _finishToken(TokenKind.VAR_DEFINITION);
+        } else if (varUsage(ch)) {
+          return _finishToken(TokenKind.VAR_USAGE);
+        } else if (TokenizerHelpers.isIdentifierStart(ch)) {
+          return finishIdentifier(ch);
+        } else if (TokenizerHelpers.isDigit(ch)) {
+          return finishNumber();
+        }
+        return _errorToken();
+    }
+  }
+
+  bool varDef(int ch) {
+    return ch == 'v'.codeUnitAt(0) && _maybeEatChar('a'.codeUnitAt(0)) &&
+        _maybeEatChar('r'.codeUnitAt(0)) && _maybeEatChar('-'.codeUnitAt(0));
+  }
+
+  bool varUsage(int ch) {
+    return ch == 'v'.codeUnitAt(0) && _maybeEatChar('a'.codeUnitAt(0)) &&
+        _maybeEatChar('r'.codeUnitAt(0)) && (_peekChar() == '-'.codeUnitAt(0));
+  }
+
+  Token _errorToken([String message = null]) {
+    return _finishToken(TokenKind.ERROR);
+  }
+
+  int getIdentifierKind() {
+    // Is the identifier a unit type?
+    int tokId = TokenKind.matchUnits(_text, _startIndex, _index - _startIndex);
+    if (tokId == -1) {
+      tokId = (_text.substring(_startIndex, _index) == '!important') ?
+          TokenKind.IMPORTANT : -1;
+    }
+
+    return tokId >= 0 ? tokId : TokenKind.IDENTIFIER;
+  }
+
+  // Need to override so CSS version of isIdentifierPart is used.
+  Token finishIdentifier(int ch) {
+    while (_index < _text.length) {
+      // If parsing in pseudo function expression then minus is an operator
+      // not part of identifier.
+      var isIdentifier = selectorExpression
+          ? TokenizerHelpers.isIdentifierPartExpr(_text.codeUnitAt(_index))
+          : TokenizerHelpers.isIdentifierPart(_text.codeUnitAt(_index));
+      if (!isIdentifier) {
+          break;
+      } else {
+        _index += 1;
+      }
+    }
+
+    int kind = getIdentifierKind();
+    if (kind == TokenKind.IDENTIFIER) {
+      return _finishToken(TokenKind.IDENTIFIER);
+    } else {
+      return _finishToken(kind);
+    }
+  }
+
+  Token finishImportant() {
+
+  }
+
+  Token finishNumber() {
+    eatDigits();
+
+    if (_peekChar() == 46/*.*/) {
+      // Handle the case of 1.toString().
+      _nextChar();
+      if (TokenizerHelpers.isDigit(_peekChar())) {
+        eatDigits();
+        return _finishToken(TokenKind.DOUBLE);
+      } else {
+        _index -= 1;
+      }
+    }
+
+    return _finishToken(TokenKind.INTEGER);
+  }
+
+  bool maybeEatDigit() {
+    if (_index < _text.length
+        && TokenizerHelpers.isDigit(_text.codeUnitAt(_index))) {
+      _index += 1;
+      return true;
+    }
+    return false;
+  }
+
+  Token finishHexNumber() {
+    eatHexDigits();
+    return _finishToken(TokenKind.HEX_INTEGER);
+  }
+
+  void eatHexDigits() {
+    while (_index < _text.length) {
+     if (TokenizerHelpers.isHexDigit(_text.codeUnitAt(_index))) {
+       _index += 1;
+     } else {
+       return;
+     }
+    }
+  }
+
+  bool maybeEatHexDigit() {
+    if (_index < _text.length
+        && TokenizerHelpers.isHexDigit(_text.codeUnitAt(_index))) {
+      _index += 1;
+      return true;
+    }
+    return false;
+  }
+
+  bool maybeEatQuestionMark() {
+    if (_index < _text.length &&
+        _text.codeUnitAt(_index) == QUESTION_MARK) {
+      _index += 1;
+      return true;
+    }
+    return false;
+  }
+
+  void eatQuestionMarks() {
+    while (_index < _text.length) {
+     if (_text.codeUnitAt(_index) == QUESTION_MARK) {
+       _index += 1;
+     } else {
+       return;
+     }
+    }
+  }
+
+  Token finishUnicodeRange() {
+    eatQuestionMarks();
+    return _finishToken(TokenKind.HEX_RANGE);
+  }
+
+  Token finishMultiLineComment() {
+    while (true) {
+      int ch = _nextChar();
+      if (ch == 0) {
+        return _finishToken(TokenKind.INCOMPLETE_COMMENT);
+      } else if (ch == 42/*'*'*/) {
+        if (_maybeEatChar(47/*'/'*/)) {
+          if (_skipWhitespace) {
+            return next();
+          } else {
+            return _finishToken(TokenKind.COMMENT);
+          }
+        }
+      } else if (ch == TokenChar.MINUS) {
+        /* Check if close part of Comment Definition --> (CDC). */
+        if (_maybeEatChar(TokenChar.MINUS)) {
+          if (_maybeEatChar(TokenChar.GREATER)) {
+            if (_skipWhitespace) {
+              return next();
+            } else {
+              return _finishToken(TokenKind.HTML_COMMENT);
+            }
+          }
+        }
+      }
+    }
+    return _errorToken();
+  }
+
+}
+
+/** Static helper methods. */
+class TokenizerHelpers {
+  static bool isIdentifierStart(int c) {
+    return isIdentifierStartExpr(c) || c == 45 /*-*/;
+  }
+
+  static bool isDigit(int c) {
+    return (c >= 48/*0*/ && c <= 57/*9*/);
+  }
+
+  static bool isHexDigit(int c) {
+    return (isDigit(c) || (c >= 97/*a*/ && c <= 102/*f*/)
+        || (c >= 65/*A*/ && c <= 70/*F*/));
+  }
+
+  static bool isIdentifierPart(int c) {
+    return isIdentifierPartExpr(c) || c == 45 /*-*/;
+  }
+
+  /** Pseudo function expressions identifiers can't have a minus sign. */
+  static bool isIdentifierStartExpr(int c) {
+    return ((c >= 97/*a*/ && c <= 122/*z*/) || (c >= 65/*A*/ && c <= 90/*Z*/) ||
+        c == 95/*_*/);
+  }
+
+  /** Pseudo function expressions identifiers can't have a minus sign. */
+  static bool isIdentifierPartExpr(int c) {
+    return (isIdentifierStartExpr(c) || isDigit(c));
+  }
+}
diff --git a/pkg/csslib/lib/src/tokenizer_base.dart b/pkg/csslib/lib/src/tokenizer_base.dart
new file mode 100644
index 0000000..f33a362
--- /dev/null
+++ b/pkg/csslib/lib/src/tokenizer_base.dart
@@ -0,0 +1,445 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Generated by scripts/tokenizer_gen.py.
+
+part of csslib.parser;
+
+/** Tokenizer state to support look ahead for Less' nested selectors. */
+class TokenizerState {
+  final int index;
+  final int startIndex;
+  final bool selectorExpression;
+
+  TokenizerState(TokenizerBase base) :
+      this.index = base._index,
+      this.startIndex = base._startIndex,
+      this.selectorExpression = base.selectorExpression;
+}
+
+/**
+ * The base class for our tokenizer. The hand coded parts are in this file, with
+ * the generated parts in the subclass Tokenizer.
+ */
+abstract class TokenizerBase {
+  final SourceFile _file;
+  final bool _skipWhitespace;
+  final String _text;
+
+  /**
+   * Changes tokenization when in a pseudo function expression.  If true then
+   * minus signs are handled as operators instead of identifiers.
+   */
+  bool selectorExpression = false;
+
+  int _index;
+  int _startIndex;
+
+  static const String _CDATA_START = '<![CDATA[';
+  static const String _CDATA_END = ']]>';
+
+  TokenizerBase(this._file, this._text, this._skipWhitespace,
+      [this._index = 0]);
+
+  Token next();
+  int getIdentifierKind();
+
+  /** Snapshot of Tokenizer scanning state. */
+  TokenizerState get mark => new TokenizerState(this);
+
+  /** Restore Tokenizer scanning state. */
+  void restore(TokenizerState markedData) {
+    _index = markedData.index;
+    _startIndex = markedData.startIndex;
+    selectorExpression = markedData.selectorExpression;
+  }
+
+  int _nextChar() {
+    if (_index < _text.length) {
+      return _text.codeUnitAt(_index++);
+    } else {
+      return 0;
+    }
+  }
+
+  int _peekChar() {
+    if (_index < _text.length) {
+      return _text.codeUnitAt(_index);
+    } else {
+      return 0;
+    }
+  }
+
+  bool _maybeEatChar(int ch) {
+    if (_index < _text.length) {
+      if (_text.codeUnitAt(_index) == ch) {
+        _index++;
+        return true;
+      } else {
+        return false;
+      }
+    } else {
+      return false;
+    }
+  }
+
+  String _tokenText() {
+    if (_index < _text.length) {
+      return _text.substring(_startIndex, _index);
+    } else {
+      return _text.substring(_startIndex, _text.length);
+    }
+  }
+
+  Token _finishToken(int kind) {
+    return new Token(kind, _file.span(_startIndex, _index));
+  }
+
+  Token _errorToken([String message = null]) {
+    return new ErrorToken(
+        TokenKind.ERROR, _file.span(_startIndex, _index), message);
+  }
+
+  Token finishWhitespace() {
+    _index--;
+    while (_index < _text.length) {
+      final ch = _text.codeUnitAt(_index++);
+      if (ch == TokenChar.SPACE ||
+          ch == TokenChar.TAB ||
+          ch == TokenChar.RETURN) {
+        // do nothing
+      } else if (ch == TokenChar.NEWLINE) {
+        if (!_skipWhitespace) {
+          return _finishToken(TokenKind.WHITESPACE); // note the newline?
+        }
+      } else {
+        _index--;
+        if (_skipWhitespace) {
+          return next();
+        } else {
+          return _finishToken(TokenKind.WHITESPACE);
+        }
+      }
+
+    }
+    return _finishToken(TokenKind.END_OF_FILE);
+  }
+
+  Token finishSingleLineComment() {
+    while (true) {
+      int ch = _nextChar();
+      if (ch == 0 || ch == TokenChar.NEWLINE || ch == TokenChar.RETURN) {
+        if (_skipWhitespace) {
+          return next();
+        } else {
+          return _finishToken(TokenKind.COMMENT);
+        }
+      }
+    }
+  }
+
+  Token finishMultiLineComment() {
+    int nesting = 1;
+    do {
+      int ch = _nextChar();
+      if (ch == 0) {
+        return _errorToken();
+      } else if (ch == TokenChar.ASTERISK) {
+        if (_maybeEatChar(TokenChar.SLASH)) {
+          nesting--;
+        }
+      } else if (ch == TokenChar.SLASH) {
+        if (_maybeEatChar(TokenChar.ASTERISK)) {
+          nesting++;
+        }
+      }
+    } while (nesting > 0);
+
+    if (_skipWhitespace) {
+      return next();
+    } else {
+      return _finishToken(TokenKind.COMMENT);
+    }
+  }
+
+  void eatDigits() {
+    while (_index < _text.length) {
+      if (TokenizerHelpers.isDigit(_text.codeUnitAt(_index))) {
+        _index++;
+      } else {
+        return;
+      }
+    }
+  }
+
+  static int _hexDigit(int c) {
+    if(c >= 48/*0*/ && c <= 57/*9*/) {
+      return c - 48;
+    } else if (c >= 97/*a*/ && c <= 102/*f*/) {
+      return c - 87;
+    } else if (c >= 65/*A*/ && c <= 70/*F*/) {
+      return c - 55;
+    } else {
+      return -1;
+    }
+  }
+
+  int readHex([int hexLength]) {
+    int maxIndex;
+    if (hexLength == null) {
+      maxIndex = _text.length - 1;
+    } else {
+      // TODO(jimhug): What if this is too long?
+      maxIndex = _index + hexLength;
+      if (maxIndex >= _text.length) return -1;
+    }
+    var result = 0;
+    while (_index < maxIndex) {
+      final digit = _hexDigit(_text.codeUnitAt(_index));
+      if (digit == -1) {
+        if (hexLength == null) {
+          return result;
+        } else {
+          return -1;
+        }
+      }
+      _hexDigit(_text.codeUnitAt(_index));
+      // Multiply by 16 rather than shift by 4 since that will result in a
+      // correct value for numbers that exceed the 32 bit precision of JS
+      // 'integers'.
+      // TODO: Figure out a better solution to integer truncation. Issue 638.
+      result = (result * 16) + digit;
+      _index++;
+    }
+
+    return result;
+  }
+
+  Token finishNumber() {
+    eatDigits();
+
+    if (_peekChar() == TokenChar.DOT) {
+      // Handle the case of 1.toString().
+      _nextChar();
+      if (TokenizerHelpers.isDigit(_peekChar())) {
+        eatDigits();
+        return finishNumberExtra(TokenKind.DOUBLE);
+      } else {
+        _index--;
+      }
+    }
+
+    return finishNumberExtra(TokenKind.INTEGER);
+  }
+
+  Token finishNumberExtra(int kind) {
+    if (_maybeEatChar(101/*e*/) || _maybeEatChar(69/*E*/)) {
+      kind = TokenKind.DOUBLE;
+      _maybeEatChar(TokenKind.MINUS);
+      _maybeEatChar(TokenKind.PLUS);
+      eatDigits();
+    }
+    if (_peekChar() != 0 && TokenizerHelpers.isIdentifierStart(_peekChar())) {
+      _nextChar();
+      return _errorToken("illegal character in number");
+    }
+
+    return _finishToken(kind);
+  }
+
+  Token _makeStringToken(List<int> buf, bool isPart) {
+    final s = new String.fromCharCodes(buf);
+    final kind = isPart ? TokenKind.STRING_PART : TokenKind.STRING;
+    return new LiteralToken(kind, _file.span(_startIndex, _index), s);
+  }
+
+  Token makeIEFilter(int start, int end) {
+    var filter = _text.substring(start, end);
+    return new LiteralToken(TokenKind.STRING, _file.span(start, end), filter);
+  }
+
+  Token _makeRawStringToken(bool isMultiline) {
+    var s;
+    if (isMultiline) {
+      // Skip initial newline in multiline strings
+      int start = _startIndex + 4;
+      if (_text[start] == '\n') start++;
+      s = _text.substring(start, _index - 3);
+    } else {
+      s = _text.substring(_startIndex + 2, _index - 1);
+    }
+    return new LiteralToken(TokenKind.STRING,
+        _file.span(_startIndex, _index), s);
+  }
+
+  Token finishMultilineString(int quote) {
+    var buf = <int>[];
+    while (true) {
+      int ch = _nextChar();
+      if (ch == 0) {
+        return _errorToken();
+      } else if (ch == quote) {
+        if (_maybeEatChar(quote)) {
+          if (_maybeEatChar(quote)) {
+            return _makeStringToken(buf, false);
+          }
+          buf.add(quote);
+        }
+        buf.add(quote);
+      } else if (ch == TokenChar.BACKSLASH) {
+        var escapeVal = readEscapeSequence();
+        if (escapeVal == -1) {
+          return _errorToken("invalid hex escape sequence");
+        } else {
+          buf.add(escapeVal);
+        }
+      } else {
+        buf.add(ch);
+      }
+    }
+  }
+
+  Token _finishOpenBrace() {
+    return _finishToken(TokenKind.LBRACE);
+  }
+
+  Token _finishCloseBrace() {
+    return _finishToken(TokenKind.RBRACE);
+  }
+
+  Token finishString(int quote) {
+    if (_maybeEatChar(quote)) {
+      if (_maybeEatChar(quote)) {
+        // skip an initial newline
+        _maybeEatChar(TokenChar.NEWLINE);
+        return finishMultilineString(quote);
+      } else {
+        return _makeStringToken(new List<int>(), false);
+      }
+    }
+    return finishStringBody(quote);
+  }
+
+  Token finishRawString(int quote) {
+    if (_maybeEatChar(quote)) {
+      if (_maybeEatChar(quote)) {
+        return finishMultilineRawString(quote);
+      } else {
+        return _makeStringToken(<int>[], false);
+      }
+    }
+    while (true) {
+      int ch = _nextChar();
+      if (ch == quote) {
+        return _makeRawStringToken(false);
+      } else if (ch == 0) {
+        return _errorToken();
+      }
+    }
+  }
+
+  Token finishMultilineRawString(int quote) {
+    while (true) {
+      int ch = _nextChar();
+      if (ch == 0) {
+        return _errorToken();
+      } else if (ch == quote && _maybeEatChar(quote) && _maybeEatChar(quote)) {
+        return _makeRawStringToken(true);
+      }
+    }
+  }
+
+  Token finishStringBody(int quote) {
+    var buf = new List<int>();
+    while (true) {
+      int ch = _nextChar();
+      if (ch == quote) {
+        return _makeStringToken(buf, false);
+      } else if (ch == 0) {
+        return _errorToken();
+      } else if (ch == TokenChar.BACKSLASH) {
+        var escapeVal = readEscapeSequence();
+        if (escapeVal == -1) {
+          return _errorToken("invalid hex escape sequence");
+        } else {
+          buf.add(escapeVal);
+        }
+      } else {
+        buf.add(ch);
+      }
+    }
+  }
+
+  int readEscapeSequence() {
+    final ch = _nextChar();
+    int hexValue;
+    switch (ch) {
+      case 110/*n*/:
+        return TokenChar.NEWLINE;
+      case 114/*r*/:
+        return TokenChar.RETURN;
+      case 102/*f*/:
+        return TokenChar.FF;
+      case 98/*b*/:
+        return TokenChar.BACKSPACE;
+      case 116/*t*/:
+        return TokenChar.TAB;
+      case 118/*v*/:
+        return TokenChar.FF;
+      case 120/*x*/:
+        hexValue = readHex(2);
+        break;
+      case 117/*u*/:
+        if (_maybeEatChar(TokenChar.LBRACE)) {
+          hexValue = readHex();
+          if (!_maybeEatChar(TokenChar.RBRACE)) {
+            return -1;
+          }
+        } else {
+          hexValue = readHex(4);
+        }
+        break;
+      default: return ch;
+    }
+
+    if (hexValue == -1) return -1;
+
+    // According to the Unicode standard the high and low surrogate halves
+    // used by UTF-16 (U+D800 through U+DFFF) and values above U+10FFFF
+    // are not legal Unicode values.
+    if (hexValue < 0xD800 || hexValue > 0xDFFF && hexValue <= 0xFFFF) {
+      return hexValue;
+    } else if (hexValue <= 0x10FFFF){
+      messages.error('unicode values greater than 2 bytes not implemented yet',
+          _file.span(_startIndex, _startIndex + 1));
+      return -1;
+    } else {
+      return -1;
+    }
+  }
+
+  Token finishDot() {
+    if (TokenizerHelpers.isDigit(_peekChar())) {
+      eatDigits();
+      return finishNumberExtra(TokenKind.DOUBLE);
+    } else {
+      return _finishToken(TokenKind.DOT);
+    }
+  }
+
+  Token finishIdentifier(int ch) {
+    while (_index < _text.length) {
+      if (!TokenizerHelpers.isIdentifierPart(_text.codeUnitAt(_index++))) {
+        _index--;
+        break;
+      }
+    }
+    int kind = getIdentifierKind();
+    if (kind == TokenKind.IDENTIFIER) {
+      return _finishToken(TokenKind.IDENTIFIER);
+    } else {
+      return _finishToken(kind);
+    }
+  }
+}
+
diff --git a/pkg/csslib/lib/src/tokenkind.dart b/pkg/csslib/lib/src/tokenkind.dart
new file mode 100644
index 0000000..ebe0615
--- /dev/null
+++ b/pkg/csslib/lib/src/tokenkind.dart
@@ -0,0 +1,756 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.parser;
+
+// TODO(terry): Need to be consistent with tokens either they're ASCII tokens
+//              e.g., ASTERISK or they're CSS e.g., PSEUDO, COMBINATOR_*.
+class TokenKind {
+  // Common shared tokens used in TokenizerBase.
+  static const int UNUSED = 0;                  // Unused place holder...
+  static const int END_OF_FILE = 1;             // EOF
+  static const int LPAREN = 2;                  // (
+  static const int RPAREN = 3;                  // )
+  static const int LBRACK = 4;                  // [
+  static const int RBRACK = 5;                  // ]
+  static const int LBRACE = 6;                  // {
+  static const int RBRACE = 7;                  // }
+  static const int DOT = 8;                     // .
+  static const int SEMICOLON = 9;               // ;
+
+  // Unique tokens for CSS.
+  static const int AT = 10;                     // @
+  static const int HASH = 11;                   // #
+  static const int PLUS = 12;                   // +
+  static const int GREATER = 13;                // >
+  static const int TILDE = 14;                  // ~
+  static const int ASTERISK = 15;               // *
+  static const int NAMESPACE = 16;              // |
+  static const int COLON = 17;                  // :
+  static const int PRIVATE_NAME = 18;           // _ prefix private class or id
+  static const int COMMA = 19;                  // ,
+  static const int SPACE = 20;
+  static const int TAB = 21;                    // /t
+  static const int NEWLINE = 22;                // /n
+  static const int RETURN = 23;                 // /r
+  static const int PERCENT = 24;                // %
+  static const int SINGLE_QUOTE = 25;           // '
+  static const int DOUBLE_QUOTE = 26;           // "
+  static const int SLASH = 27;                  // /
+  static const int EQUALS = 28;                 // =
+  static const int OR = 29;                     // |
+  static const int CARET = 30;                  // ^
+  static const int DOLLAR = 31;                 // $
+  static const int LESS = 32;                   // <
+  static const int BANG = 33;                   // !
+  static const int MINUS = 34;                  // -
+  static const int BACKSLASH = 35;              // \
+  static const int AMPERSAND = 36;              // &
+
+  // WARNING: Tokens from this point and above must have the corresponding ASCII
+  //          character in the TokenChar list at the bottom of this file.  The
+  //          order of the above tokens should be the same order as TokenChar.
+
+  /** [TokenKind] representing integer tokens. */
+  static const int INTEGER = 60;
+
+  /** [TokenKind] representing hex integer tokens. */
+  static const int HEX_INTEGER = 61;
+
+  /** [TokenKind] representing double tokens. */
+  static const int DOUBLE = 62;
+
+  /** [TokenKind] representing whitespace tokens. */
+  static const int WHITESPACE = 63;
+
+  /** [TokenKind] representing comment tokens. */
+  static const int COMMENT = 64;
+
+  /** [TokenKind] representing error tokens. */
+  static const int ERROR = 65;
+
+  /** [TokenKind] representing incomplete string tokens. */
+  static const int INCOMPLETE_STRING = 66;
+
+  /** [TokenKind] representing incomplete comment tokens. */
+  static const int INCOMPLETE_COMMENT = 67;
+
+  static const int VAR_DEFINITION = 400;        // var-NNN-NNN
+  static const int VAR_USAGE = 401;             // var(NNN-NNN [,default])
+
+  // Synthesized Tokens (no character associated with TOKEN).
+  static const int STRING = 500;
+  static const int STRING_PART = 501;
+  static const int NUMBER = 502;
+  static const int HEX_NUMBER = 503;
+  static const int HTML_COMMENT = 504;          // <!--
+  static const int IMPORTANT = 505;             // !important
+  static const int CDATA_START = 506;           // <![CDATA[
+  static const int CDATA_END = 507;             // ]]>
+  // U+uNumber[-U+uNumber]
+  // uNumber = 0..10FFFF | ?[?]*
+  static const int UNICODE_RANGE = 508;
+  static const int HEX_RANGE = 509;             // ? in the hex range
+  static const int IDENTIFIER = 511;
+
+  // Uniquely synthesized tokens for CSS.
+  static const int SELECTOR_EXPRESSION = 512;
+  static const int COMBINATOR_NONE = 513;
+  static const int COMBINATOR_DESCENDANT = 514; // Space combinator
+  static const int COMBINATOR_PLUS = 515;       // + combinator
+  static const int COMBINATOR_GREATER = 516;    // > combinator
+  static const int COMBINATOR_TILDE = 517;      // ~ combinator
+
+  static const int UNARY_OP_NONE = 518;         // No unary operator present.
+
+  // Attribute match types:
+  static const int INCLUDES = 530;              // '~='
+  static const int DASH_MATCH = 531;            // '|='
+  static const int PREFIX_MATCH = 532;          // '^='
+  static const int SUFFIX_MATCH = 533;          // '$='
+  static const int SUBSTRING_MATCH = 534;       // '*='
+  static const int NO_MATCH = 535;              // No operator.
+
+  // Unit types:
+  static const int UNIT_EM = 600;
+  static const int UNIT_EX = 601;
+  static const int UNIT_LENGTH_PX = 602;
+  static const int UNIT_LENGTH_CM = 603;
+  static const int UNIT_LENGTH_MM = 604;
+  static const int UNIT_LENGTH_IN = 605;
+  static const int UNIT_LENGTH_PT = 606;
+  static const int UNIT_LENGTH_PC = 607;
+  static const int UNIT_ANGLE_DEG = 608;
+  static const int UNIT_ANGLE_RAD = 609;
+  static const int UNIT_ANGLE_GRAD = 610;
+  static const int UNIT_ANGLE_TURN = 611;
+  static const int UNIT_TIME_MS = 612;
+  static const int UNIT_TIME_S = 613;
+  static const int UNIT_FREQ_HZ = 614;
+  static const int UNIT_FREQ_KHZ = 615;
+  static const int UNIT_PERCENT = 616;
+  static const int UNIT_FRACTION = 617;
+  static const int UNIT_RESOLUTION_DPI = 618;
+  static const int UNIT_RESOLUTION_DPCM = 619;
+  static const int UNIT_RESOLUTION_DPPX = 620;
+  static const int UNIT_CH = 621;   // Measure of "0" U+0030 glyph.
+  static const int UNIT_REM = 622;  // computed value ‘font-size’ on root elem.
+  static const int UNIT_VIEWPORT_VW = 623;
+  static const int UNIT_VIEWPORT_VH = 624;
+  static const int UNIT_VIEWPORT_VMIN = 625;
+  static const int UNIT_VIEWPORT_VMAX = 626;
+
+  // Directives (@nnnn)
+  static const int DIRECTIVE_NONE = 650;
+  static const int DIRECTIVE_IMPORT = 651;
+  static const int DIRECTIVE_MEDIA = 652;
+  static const int DIRECTIVE_PAGE = 653;
+  static const int DIRECTIVE_CHARSET = 654;
+  static const int DIRECTIVE_STYLET = 655;
+  static const int DIRECTIVE_KEYFRAMES = 656;
+  static const int DIRECTIVE_WEB_KIT_KEYFRAMES = 657;
+  static const int DIRECTIVE_MOZ_KEYFRAMES = 658;
+  static const int DIRECTIVE_MS_KEYFRAMES = 659;
+  static const int DIRECTIVE_O_KEYFRAMES = 660;
+  static const int DIRECTIVE_FONTFACE = 661;
+  static const int DIRECTIVE_NAMESPACE = 662;
+  static const int DIRECTIVE_HOST = 663;
+
+  // Media query operators
+  static const int MEDIA_OP_ONLY = 665;     // Unary.
+  static const int MEDIA_OP_NOT = 666;      // Unary.
+  static const int MEDIA_OP_AND = 667;      // Binary.
+
+  // Directives inside of a @page (margin sym).
+  static const int MARGIN_DIRECTIVE_TOPLEFTCORNER = 670;
+  static const int MARGIN_DIRECTIVE_TOPLEFT = 671;
+  static const int MARGIN_DIRECTIVE_TOPCENTER = 672;
+  static const int MARGIN_DIRECTIVE_TOPRIGHT = 673;
+  static const int MARGIN_DIRECTIVE_TOPRIGHTCORNER = 674;
+  static const int MARGIN_DIRECTIVE_BOTTOMLEFTCORNER = 675;
+  static const int MARGIN_DIRECTIVE_BOTTOMLEFT = 676;
+  static const int MARGIN_DIRECTIVE_BOTTOMCENTER = 677;
+  static const int MARGIN_DIRECTIVE_BOTTOMRIGHT = 678;
+  static const int MARGIN_DIRECTIVE_BOTTOMRIGHTCORNER = 679;
+  static const int MARGIN_DIRECTIVE_LEFTTOP = 680;
+  static const int MARGIN_DIRECTIVE_LEFTMIDDLE = 681;
+  static const int MARGIN_DIRECTIVE_LEFTBOTTOM = 682;
+  static const int MARGIN_DIRECTIVE_RIGHTTOP = 683;
+  static const int MARGIN_DIRECTIVE_RIGHTMIDDLE = 684;
+  static const int MARGIN_DIRECTIVE_RIGHTBOTTOM = 685;
+
+  // Simple selector type.
+  static const int CLASS_NAME = 700;            // .class
+  static const int ELEMENT_NAME = 701;          // tagName
+  static const int HASH_NAME = 702;             // #elementId
+  static const int ATTRIBUTE_NAME = 703;        // [attrib]
+  static const int PSEUDO_ELEMENT_NAME = 704;   // ::pseudoElement
+  static const int PSEUDO_CLASS_NAME = 705;     // :pseudoClass
+  static const int NEGATION = 706;              // NOT
+
+  static const List<Map<int, String>> _DIRECTIVES = const [
+    const {'type': TokenKind.DIRECTIVE_IMPORT, 'value' : 'import'},
+    const {'type': TokenKind.DIRECTIVE_MEDIA, 'value' : 'media'},
+    const {'type': TokenKind.DIRECTIVE_PAGE, 'value' : 'page'},
+    const {'type': TokenKind.DIRECTIVE_CHARSET, 'value' : 'charset'},
+    const {'type': TokenKind.DIRECTIVE_STYLET, 'value' : 'stylet'},
+    const {'type': TokenKind.DIRECTIVE_KEYFRAMES, 'value' : 'keyframes'},
+    const {'type': TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES,
+        'value' : '-webkit-keyframes'},
+    const {'type': TokenKind.DIRECTIVE_MOZ_KEYFRAMES,
+          'value' : '-moz-keyframes'},
+    const {'type': TokenKind.DIRECTIVE_MS_KEYFRAMES, 'value' : '-ms-keyframes'},
+    const {'type': TokenKind.DIRECTIVE_O_KEYFRAMES, 'value' : '-o-keyframes'},
+    const {'type': TokenKind.DIRECTIVE_FONTFACE, 'value' : 'font-face'},
+    const {'type': TokenKind.DIRECTIVE_NAMESPACE, 'value' : 'namespace'},
+    const {'type': TokenKind.DIRECTIVE_HOST, 'value' : 'host'},
+  ];
+
+  static const List<Map<int, String>> MEDIA_OPERATORS = const [
+    const {'type': TokenKind.MEDIA_OP_ONLY, 'value' : 'only'},
+    const {'type': TokenKind.MEDIA_OP_NOT, 'value' : 'not'},
+    const {'type': TokenKind.MEDIA_OP_AND, 'value' : 'and'},
+];
+
+  static const List<Map<int, String>> MARGIN_DIRECTIVES = const [
+    const {'type': TokenKind.MARGIN_DIRECTIVE_TOPLEFTCORNER,
+        'value' : 'top-left-corner'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_TOPLEFT,
+        'value' : 'top-left'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_TOPCENTER,
+        'value' : 'top-center'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_TOPRIGHT,
+        'value' : 'top-right'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_TOPRIGHTCORNER,
+        'value' : 'top-right-corner'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFTCORNER,
+        'value' : 'bottom-left-corner'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFT,
+        'value' : 'bottom-left'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMCENTER,
+        'value' : 'bottom-center'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHT,
+        'value' : 'bottom-right'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHTCORNER,
+        'value' : 'bottom-right-corner'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_LEFTTOP,
+        'value' : 'left-top'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_LEFTMIDDLE,
+        'value' : 'left-middle'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_LEFTBOTTOM,
+        'value' : 'right-bottom'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_RIGHTTOP,
+        'value' : 'right-top'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_RIGHTMIDDLE,
+        'value' : 'right-middle'},
+    const {'type': TokenKind.MARGIN_DIRECTIVE_RIGHTBOTTOM,
+        'value' : 'right-bottom'},
+  ];
+
+  static const List<Map> _UNITS = const [
+    const {'unit': TokenKind.UNIT_EM, 'value' : 'em'},
+    const {'unit': TokenKind.UNIT_EX, 'value' : 'ex'},
+    const {'unit': TokenKind.UNIT_LENGTH_PX, 'value' : 'px'},
+    const {'unit': TokenKind.UNIT_LENGTH_CM, 'value' : 'cm'},
+    const {'unit': TokenKind.UNIT_LENGTH_MM, 'value' : 'mm'},
+    const {'unit': TokenKind.UNIT_LENGTH_IN, 'value' : 'in'},
+    const {'unit': TokenKind.UNIT_LENGTH_PT, 'value' : 'pt'},
+    const {'unit': TokenKind.UNIT_LENGTH_PC, 'value' : 'pc'},
+    const {'unit': TokenKind.UNIT_ANGLE_DEG, 'value' : 'deg'},
+    const {'unit': TokenKind.UNIT_ANGLE_RAD, 'value' : 'rad'},
+    const {'unit': TokenKind.UNIT_ANGLE_GRAD, 'value' : 'grad'},
+    const {'unit': TokenKind.UNIT_ANGLE_TURN, 'value' : 'turn'},
+    const {'unit': TokenKind.UNIT_TIME_MS, 'value' : 'ms'},
+    const {'unit': TokenKind.UNIT_TIME_S, 'value' : 's'},
+    const {'unit': TokenKind.UNIT_FREQ_HZ, 'value' : 'hz'},
+    const {'unit': TokenKind.UNIT_FREQ_KHZ, 'value' : 'khz'},
+    const {'unit': TokenKind.UNIT_FRACTION, 'value' : 'fr'},
+    const {'unit': TokenKind.UNIT_RESOLUTION_DPI, 'value' : 'dpi'},
+    const {'unit': TokenKind.UNIT_RESOLUTION_DPCM, 'value' : 'dpcm'},
+    const {'unit': TokenKind.UNIT_RESOLUTION_DPPX, 'value' : 'dppx'},
+    const {'unit': TokenKind.UNIT_CH, 'value' : 'ch'},
+    const {'unit': TokenKind.UNIT_REM, 'value' : 'rem'},
+    const {'unit': TokenKind.UNIT_VIEWPORT_VW, 'value' : 'vw'},
+    const {'unit': TokenKind.UNIT_VIEWPORT_VH, 'value' : 'vh'},
+    const {'unit': TokenKind.UNIT_VIEWPORT_VMIN, 'value' : 'vmin'},
+    const {'unit': TokenKind.UNIT_VIEWPORT_VMAX, 'value' : 'vmax'},
+    ];
+
+  // Some more constants:
+  static const int ASCII_UPPER_A = 65;    // ASCII value for uppercase A
+  static const int ASCII_UPPER_Z = 90;    // ASCII value for uppercase Z
+
+  // Extended color keywords:
+  static const List<Map> _EXTENDED_COLOR_NAMES = const [
+    const {'name' : 'aliceblue', 'value' : 0xF08FF},
+    const {'name' : 'antiquewhite', 'value' : 0xFAEBD7},
+    const {'name' : 'aqua', 'value' : 0x00FFFF},
+    const {'name' : 'aquamarine', 'value' : 0x7FFFD4},
+    const {'name' : 'azure', 'value' : 0xF0FFFF},
+    const {'name' : 'beige', 'value' : 0xF5F5DC},
+    const {'name' : 'bisque', 'value' : 0xFFE4C4},
+    const {'name' : 'black', 'value' : 0x000000},
+    const {'name' : 'blanchedalmond', 'value' : 0xFFEBCD},
+    const {'name' : 'blue', 'value' : 0x0000FF},
+    const {'name' : 'blueviolet', 'value' : 0x8A2BE2},
+    const {'name' : 'brown', 'value' : 0xA52A2A},
+    const {'name' : 'burlywood', 'value' : 0xDEB887},
+    const {'name' : 'cadetblue', 'value' : 0x5F9EA0},
+    const {'name' : 'chartreuse', 'value' : 0x7FFF00},
+    const {'name' : 'chocolate', 'value' : 0xD2691E},
+    const {'name' : 'coral', 'value' : 0xFF7F50},
+    const {'name' : 'cornflowerblue', 'value' : 0x6495ED},
+    const {'name' : 'cornsilk', 'value' : 0xFFF8DC},
+    const {'name' : 'crimson', 'value' : 0xDC143C},
+    const {'name' : 'cyan', 'value' : 0x00FFFF},
+    const {'name' : 'darkblue', 'value' : 0x00008B},
+    const {'name' : 'darkcyan', 'value' : 0x008B8B},
+    const {'name' : 'darkgoldenrod', 'value' : 0xB8860B},
+    const {'name' : 'darkgray', 'value' : 0xA9A9A9},
+    const {'name' : 'darkgreen', 'value' : 0x006400},
+    const {'name' : 'darkgrey', 'value' : 0xA9A9A9},
+    const {'name' : 'darkkhaki', 'value' : 0xBDB76B},
+    const {'name' : 'darkmagenta', 'value' : 0x8B008B},
+    const {'name' : 'darkolivegreen', 'value' : 0x556B2F},
+    const {'name' : 'darkorange', 'value' : 0xFF8C00},
+    const {'name' : 'darkorchid', 'value' : 0x9932CC},
+    const {'name' : 'darkred', 'value' : 0x8B0000},
+    const {'name' : 'darksalmon', 'value' : 0xE9967A},
+    const {'name' : 'darkseagreen', 'value' : 0x8FBC8F},
+    const {'name' : 'darkslateblue', 'value' : 0x483D8B},
+    const {'name' : 'darkslategray', 'value' : 0x2F4F4F},
+    const {'name' : 'darkslategrey', 'value' : 0x2F4F4F},
+    const {'name' : 'darkturquoise', 'value' : 0x00CED1},
+    const {'name' : 'darkviolet', 'value' : 0x9400D3},
+    const {'name' : 'deeppink', 'value' : 0xFF1493},
+    const {'name' : 'deepskyblue', 'value' : 0x00BFFF},
+    const {'name' : 'dimgray', 'value' : 0x696969},
+    const {'name' : 'dimgrey', 'value' : 0x696969},
+    const {'name' : 'dodgerblue', 'value' : 0x1E90FF},
+    const {'name' : 'firebrick', 'value' : 0xB22222},
+    const {'name' : 'floralwhite', 'value' : 0xFFFAF0},
+    const {'name' : 'forestgreen', 'value' : 0x228B22},
+    const {'name' : 'fuchsia', 'value' : 0xFF00FF},
+    const {'name' : 'gainsboro', 'value' : 0xDCDCDC},
+    const {'name' : 'ghostwhite', 'value' : 0xF8F8FF},
+    const {'name' : 'gold', 'value' : 0xFFD700},
+    const {'name' : 'goldenrod', 'value' : 0xDAA520},
+    const {'name' : 'gray', 'value' : 0x808080},
+    const {'name' : 'green', 'value' : 0x008000},
+    const {'name' : 'greenyellow', 'value' : 0xADFF2F},
+    const {'name' : 'grey', 'value' : 0x808080},
+    const {'name' : 'honeydew', 'value' : 0xF0FFF0},
+    const {'name' : 'hotpink', 'value' : 0xFF69B4},
+    const {'name' : 'indianred', 'value' : 0xCD5C5C},
+    const {'name' : 'indigo', 'value' : 0x4B0082},
+    const {'name' : 'ivory', 'value' : 0xFFFFF0},
+    const {'name' : 'khaki', 'value' : 0xF0E68C},
+    const {'name' : 'lavender', 'value' : 0xE6E6FA},
+    const {'name' : 'lavenderblush', 'value' : 0xFFF0F5},
+    const {'name' : 'lawngreen', 'value' : 0x7CFC00},
+    const {'name' : 'lemonchiffon', 'value' : 0xFFFACD},
+    const {'name' : 'lightblue', 'value' : 0xADD8E6},
+    const {'name' : 'lightcoral', 'value' : 0xF08080},
+    const {'name' : 'lightcyan', 'value' : 0xE0FFFF},
+    const {'name' : 'lightgoldenrodyellow', 'value' : 0xFAFAD2},
+    const {'name' : 'lightgray', 'value' : 0xD3D3D3},
+    const {'name' : 'lightgreen', 'value' : 0x90EE90},
+    const {'name' : 'lightgrey', 'value' : 0xD3D3D3},
+    const {'name' : 'lightpink', 'value' : 0xFFB6C1},
+    const {'name' : 'lightsalmon', 'value' : 0xFFA07A},
+    const {'name' : 'lightseagreen', 'value' : 0x20B2AA},
+    const {'name' : 'lightskyblue', 'value' : 0x87CEFA},
+    const {'name' : 'lightslategray', 'value' : 0x778899},
+    const {'name' : 'lightslategrey', 'value' : 0x778899},
+    const {'name' : 'lightsteelblue', 'value' : 0xB0C4DE},
+    const {'name' : 'lightyellow', 'value' : 0xFFFFE0},
+    const {'name' : 'lime', 'value' : 0x00FF00},
+    const {'name' : 'limegreen', 'value' : 0x32CD32},
+    const {'name' : 'linen', 'value' : 0xFAF0E6},
+    const {'name' : 'magenta', 'value' : 0xFF00FF},
+    const {'name' : 'maroon', 'value' : 0x800000},
+    const {'name' : 'mediumaquamarine', 'value' : 0x66CDAA},
+    const {'name' : 'mediumblue', 'value' : 0x0000CD},
+    const {'name' : 'mediumorchid', 'value' : 0xBA55D3},
+    const {'name' : 'mediumpurple', 'value' : 0x9370DB},
+    const {'name' : 'mediumseagreen', 'value' : 0x3CB371},
+    const {'name' : 'mediumslateblue', 'value' : 0x7B68EE},
+    const {'name' : 'mediumspringgreen', 'value' : 0x00FA9A},
+    const {'name' : 'mediumturquoise', 'value' : 0x48D1CC},
+    const {'name' : 'mediumvioletred', 'value' : 0xC71585},
+    const {'name' : 'midnightblue', 'value' : 0x191970},
+    const {'name' : 'mintcream', 'value' : 0xF5FFFA},
+    const {'name' : 'mistyrose', 'value' : 0xFFE4E1},
+    const {'name' : 'moccasin', 'value' : 0xFFE4B5},
+    const {'name' : 'navajowhite', 'value' : 0xFFDEAD},
+    const {'name' : 'navy', 'value' : 0x000080},
+    const {'name' : 'oldlace', 'value' : 0xFDF5E6},
+    const {'name' : 'olive', 'value' : 0x808000},
+    const {'name' : 'olivedrab', 'value' : 0x6B8E23},
+    const {'name' : 'orange', 'value' : 0xFFA500},
+    const {'name' : 'orangered', 'value' : 0xFF4500},
+    const {'name' : 'orchid', 'value' : 0xDA70D6},
+    const {'name' : 'palegoldenrod', 'value' : 0xEEE8AA},
+    const {'name' : 'palegreen', 'value' : 0x98FB98},
+    const {'name' : 'paleturquoise', 'value' : 0xAFEEEE},
+    const {'name' : 'palevioletred', 'value' : 0xDB7093},
+    const {'name' : 'papayawhip', 'value' : 0xFFEFD5},
+    const {'name' : 'peachpuff', 'value' : 0xFFDAB9},
+    const {'name' : 'peru', 'value' : 0xCD853F},
+    const {'name' : 'pink', 'value' : 0xFFC0CB},
+    const {'name' : 'plum', 'value' : 0xDDA0DD},
+    const {'name' : 'powderblue', 'value' : 0xB0E0E6},
+    const {'name' : 'purple', 'value' : 0x800080},
+    const {'name' : 'red', 'value' : 0xFF0000},
+    const {'name' : 'rosybrown', 'value' : 0xBC8F8F},
+    const {'name' : 'royalblue', 'value' : 0x4169E1},
+    const {'name' : 'saddlebrown', 'value' : 0x8B4513},
+    const {'name' : 'salmon', 'value' : 0xFA8072},
+    const {'name' : 'sandybrown', 'value' : 0xF4A460},
+    const {'name' : 'seagreen', 'value' : 0x2E8B57},
+    const {'name' : 'seashell', 'value' : 0xFFF5EE},
+    const {'name' : 'sienna', 'value' : 0xA0522D},
+    const {'name' : 'silver', 'value' : 0xC0C0C0},
+    const {'name' : 'skyblue', 'value' : 0x87CEEB},
+    const {'name' : 'slateblue', 'value' : 0x6A5ACD},
+    const {'name' : 'slategray', 'value' : 0x708090},
+    const {'name' : 'slategrey', 'value' : 0x708090},
+    const {'name' : 'snow', 'value' : 0xFFFAFA},
+    const {'name' : 'springgreen', 'value' : 0x00FF7F},
+    const {'name' : 'steelblue', 'value' : 0x4682B4},
+    const {'name' : 'tan', 'value' : 0xD2B48C},
+    const {'name' : 'teal', 'value' : 0x008080},
+    const {'name' : 'thistle', 'value' : 0xD8BFD8},
+    const {'name' : 'tomato', 'value' : 0xFF6347},
+    const {'name' : 'turquoise', 'value' : 0x40E0D0},
+    const {'name' : 'violet', 'value' : 0xEE82EE},
+    const {'name' : 'wheat', 'value' : 0xF5DEB3},
+    const {'name' : 'white', 'value' : 0xFFFFFF},
+    const {'name' : 'whitesmoke', 'value' : 0xF5F5F5},
+    const {'name' : 'yellow', 'value' : 0xFFFF00},
+    const {'name' : 'yellowgreen', 'value' : 0x9ACD32},
+  ];
+
+  // TODO(terry): Should used Dart mirroring for parameter values and types
+  //              especially for enumeration (e.g., counter's second parameter
+  //              is list-style-type which is an enumerated list for ordering
+  //              of a list 'circle', 'decimal', 'lower-roman', 'square', etc.
+  //              see http://www.w3schools.com/cssref/pr_list-style-type.asp
+  //              for list of possible values.
+
+  // List of valid CSS functions:
+  static const List<Map<String, Object>> _FUNCTIONS = const [
+    const {'name' : 'counter', 'info' : const {'params' : 2, 'expr' : false}},
+    const {'name' : 'attr', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'calc', 'info' : const {'params' : 1, 'expr' : true}},
+    const {'name' : 'min', 'info' : const {'params' : 2, 'expr' : true}},
+    const {'name' : 'max', 'info' : const {'params' : 2, 'expr' : true}},
+
+    // 2D functions:
+    const {'name' : 'translateX',
+        'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'translateY',
+        'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'translate', 'info' : const {'params' : 2, 'expr' : false}},
+    const {'name' : 'rotate', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'scaleX', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'scaleY', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'scale', 'info' : const {'params' : 2, 'expr' : false}},
+    const {'name' : 'skewX', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'skewY', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'skew', 'info' : const {'params' : 2, 'expr' : false}},
+    const {'name' : 'matrix', 'info' : const {'params' : 6, 'expr' : false}},
+
+    // 3D functions:
+    const {'name' : 'matrix3d', 'info' : const {'params' : 16, 'expr' : false}},
+    const {'name' : 'translate3d',
+        'info' : const {'params' : 3, 'expr' : false}},
+    const {'name' : 'translateZ',
+        'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'scale3d', 'info' : const {'params' : 3, 'expr' : false}},
+    const {'name' : 'scaleZ', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'rotate3d', 'info' : const {'params' : 3, 'expr' : false}},
+    const {'name' : 'rotateX', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'rotateY', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'rotateZ', 'info' : const {'params' : 1, 'expr' : false}},
+    const {'name' : 'perspective',
+        'info' : const {'params' : 1, 'expr' : false}},
+  ];
+
+  /**
+   * Check if name is a pre-defined CSS name.  Used by error handler to report
+   * if name is unknown or used improperly.
+   */
+  static bool isPredefinedName(String name) {
+    var nameLen = name.length;
+    // TODO(terry): Add more pre-defined names (hidden, bolder, inherit, etc.).
+    if (matchUnits(name, 0, nameLen) == -1 ||
+        matchDirectives(name, 0, nameLen) == -1 ||
+        matchMarginDirectives(name, 0, nameLen) == -1 ||
+        matchColorName(name) == null) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /** Return the token that matches the unit ident found. */
+  static int matchList(var identList, String tokenField, String text,
+                       int offset, int length) {
+    for (final entry in identList) {
+      String ident = entry['value'];
+
+      if (length == ident.length) {
+        int idx = offset;
+        bool match = true;
+        for (int i = 0; i < ident.length; i++) {
+          int identChar = ident.codeUnitAt(i);
+          int char = text.codeUnitAt(idx++);
+          // Compare lowercase to lowercase then check if char is uppercase.
+          match = match && (char == identChar ||
+              ((char >= ASCII_UPPER_A && char <= ASCII_UPPER_Z) &&
+               (char + 32) == identChar));
+          if (!match) {
+            break;
+          }
+        }
+
+        if (match) {
+          // Completely matched; return the token for this unit.
+          return entry[tokenField];
+        }
+      }
+    }
+
+    return -1;  // Not a unit token.
+  }
+
+  /** Return the token that matches the unit ident found. */
+  static int matchUnits(String text, int offset, int length) {
+    return matchList(_UNITS, 'unit', text, offset, length);
+  }
+
+  /** Return the token that matches the directive name found. */
+  static int matchDirectives(String text, int offset, int length) {
+    return matchList(_DIRECTIVES, 'type', text, offset, length);
+  }
+
+  /** Return the token that matches the margin directive name found. */
+  static int matchMarginDirectives(String text, int offset, int length) {
+    return matchList(MARGIN_DIRECTIVES, 'type', text, offset, length);
+  }
+
+  /** Return the token that matches the media operator found. */
+  static int matchMediaOperator(String text, int offset, int length) {
+    return matchList(MEDIA_OPERATORS, 'type', text, offset, length);
+  }
+
+  static String idToValue(var identList, int tokenId) {
+    for (var entry in identList) {
+      if (tokenId == entry['type']) {
+        return entry['value'];
+      }
+    }
+
+    return null;
+  }
+
+
+  /** Return the unit token as its pretty name. */
+  static String unitToString(int unitTokenToFind) {
+    if (unitTokenToFind == TokenKind.PERCENT) {
+      return '%';
+    } else {
+      for (final entry in _UNITS) {
+        int unit = entry['unit'];
+        if (unit == unitTokenToFind) {
+          return entry['value'];
+        }
+      }
+    }
+
+    return '<BAD UNIT>';  // Not a unit token.
+  }
+
+  /**
+   * Match color name, case insensitive match and return the associated color
+   * entry from _EXTENDED_COLOR_NAMES list, return [null] if not found.
+   */
+  static Map matchColorName(String text) {
+    var name = text.toLowerCase();
+    return _EXTENDED_COLOR_NAMES.
+        firstWhere((e) => e['name'] == name, orElse: () => null);
+  }
+
+  /** Return RGB value as [int] from a color entry in _EXTENDED_COLOR_NAMES. */
+  static int colorValue(Map entry) {
+    assert(entry != null);
+    return entry['value'];
+  }
+
+  static String hexToColorName(hexValue) {
+    for (final entry in _EXTENDED_COLOR_NAMES) {
+      if (entry['value'] == hexValue) {
+        return entry['name'];
+      }
+    }
+
+    return null;
+  }
+
+  static String decimalToHex(int number, [int minDigits = 1]) {
+    final String _HEX_DIGITS = '0123456789abcdef';
+
+    List<String> result = new List<String>();
+
+    int dividend = number >> 4;
+    int remain = number % 16;
+    result.add(_HEX_DIGITS[remain]);
+    while (dividend != 0) {
+      remain = dividend % 16;
+      dividend >>= 4;
+      result.add(_HEX_DIGITS[remain]);
+    }
+
+    StringBuffer invertResult = new StringBuffer();
+    int paddings = minDigits - result.length;
+    while (paddings-- > 0) {
+      invertResult.write('0');
+    }
+    for (int i = result.length - 1; i >= 0; i--) {
+      invertResult.write(result[i]);
+    }
+
+    return invertResult.toString();
+  }
+
+  static String kindToString(int kind) {
+    switch(kind) {
+      case TokenKind.UNUSED: return "ERROR";
+      case TokenKind.END_OF_FILE: return "end of file";
+      case TokenKind.LPAREN: return "(";
+      case TokenKind.RPAREN: return ")";
+      case TokenKind.LBRACK: return "[";
+      case TokenKind.RBRACK: return "]";
+      case TokenKind.LBRACE: return "{";
+      case TokenKind.RBRACE: return "}";
+      case TokenKind.DOT: return ".";
+      case TokenKind.SEMICOLON: return ";";
+      case TokenKind.AT: return "@";
+      case TokenKind.HASH: return "#";
+      case TokenKind.PLUS: return "+";
+      case TokenKind.GREATER: return ">";
+      case TokenKind.TILDE: return "~";
+      case TokenKind.ASTERISK: return "*";
+      case TokenKind.NAMESPACE: return "|";
+      case TokenKind.COLON: return ":";
+      case TokenKind.PRIVATE_NAME: return "_";
+      case TokenKind.COMMA: return ",";
+      case TokenKind.SPACE: return " ";
+      case TokenKind.TAB: return "\t";
+      case TokenKind.NEWLINE: return "\n";
+      case TokenKind.RETURN: return "\r";
+      case TokenKind.PERCENT: return "%";
+      case TokenKind.SINGLE_QUOTE: return "'";
+      case TokenKind.DOUBLE_QUOTE: return "\"";
+      case TokenKind.SLASH: return "/";
+      case TokenKind.EQUALS: return '=';
+      case TokenKind.OR: return '|';
+      case TokenKind.CARET: return '^';
+      case TokenKind.DOLLAR: return '\$';
+      case TokenKind.LESS: return '<';
+      case TokenKind.BANG: return '!';
+      case TokenKind.MINUS: return '-';
+      case TokenKind.BACKSLASH: return '\\';
+      default:
+        throw "Unknown TOKEN";
+    }
+  }
+
+  static bool isKindIdentifier(int kind) {
+    switch(kind) {
+      // Synthesized tokens.
+      case TokenKind.DIRECTIVE_IMPORT:
+      case TokenKind.DIRECTIVE_MEDIA:
+      case TokenKind.DIRECTIVE_PAGE:
+      case TokenKind.DIRECTIVE_CHARSET:
+      case TokenKind.DIRECTIVE_STYLET:
+      case TokenKind.DIRECTIVE_KEYFRAMES:
+      case TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES:
+      case TokenKind.DIRECTIVE_MOZ_KEYFRAMES:
+      case TokenKind.DIRECTIVE_MS_KEYFRAMES:
+      case TokenKind.DIRECTIVE_O_KEYFRAMES:
+      case TokenKind.DIRECTIVE_FONTFACE:
+      case TokenKind.DIRECTIVE_NAMESPACE:
+      case TokenKind.DIRECTIVE_HOST:
+      case TokenKind.UNIT_EM:
+      case TokenKind.UNIT_EX:
+      case TokenKind.UNIT_LENGTH_PX:
+      case TokenKind.UNIT_LENGTH_CM:
+      case TokenKind.UNIT_LENGTH_MM:
+      case TokenKind.UNIT_LENGTH_IN:
+      case TokenKind.UNIT_LENGTH_PT:
+      case TokenKind.UNIT_LENGTH_PC:
+      case TokenKind.UNIT_ANGLE_DEG:
+      case TokenKind.UNIT_ANGLE_RAD:
+      case TokenKind.UNIT_ANGLE_GRAD:
+      case TokenKind.UNIT_TIME_MS:
+      case TokenKind.UNIT_TIME_S:
+      case TokenKind.UNIT_FREQ_HZ:
+      case TokenKind.UNIT_FREQ_KHZ:
+      case TokenKind.UNIT_FRACTION:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  static bool isIdentifier(int kind) {
+    return kind == IDENTIFIER ;
+  }
+}
+
+// Note: these names should match TokenKind names
+class TokenChar {
+  static const int UNUSED = -1;
+  static const int END_OF_FILE = 0;
+  static const int LPAREN = 0x28; // "(".codeUnitAt(0)
+  static const int RPAREN = 0x29; // ")".codeUnitAt(0)
+  static const int LBRACK = 0x5b; // "[".codeUnitAt(0)
+  static const int RBRACK = 0x5d; // "]".codeUnitAt(0)
+  static const int LBRACE = 0x7b; // "{".codeUnitAt(0)
+  static const int RBRACE = 0x7d; // "}".codeUnitAt(0)
+  static const int DOT = 0x2e; // ".".codeUnitAt(0)
+  static const int SEMICOLON = 0x3b; // ";".codeUnitAt(0)
+  static const int AT = 0x40; // "@".codeUnitAt(0)
+  static const int HASH = 0x23; // "#".codeUnitAt(0)
+  static const int PLUS = 0x2b; // "+".codeUnitAt(0)
+  static const int GREATER = 0x3e; // ">".codeUnitAt(0)
+  static const int TILDE = 0x7e; // "~".codeUnitAt(0)
+  static const int ASTERISK = 0x2a; // "*".codeUnitAt(0)
+  static const int NAMESPACE = 0x7c; // "|".codeUnitAt(0)
+  static const int COLON = 0x3a; // ":".codeUnitAt(0)
+  static const int PRIVATE_NAME = 0x5f; // "_".codeUnitAt(0)
+  static const int COMMA = 0x2c; // ",".codeUnitAt(0)
+  static const int SPACE = 0x20; // " ".codeUnitAt(0)
+  static const int TAB = 0x9; // "\t".codeUnitAt(0)
+  static const int NEWLINE = 0xa; // "\n".codeUnitAt(0)
+  static const int RETURN = 0xd; // "\r".codeUnitAt(0)
+  static const int BACKSPACE = 0x8; // "/b".codeUnitAt(0)
+  static const int FF = 0xc; // "/f".codeUnitAt(0)
+  static const int VT = 0xb; // "/v".codeUnitAt(0)
+  static const int PERCENT = 0x25; // "%".codeUnitAt(0)
+  static const int SINGLE_QUOTE = 0x27; // "'".codeUnitAt(0)
+  static const int DOUBLE_QUOTE = 0x22; // '"'.codeUnitAt(0)
+  static const int SLASH = 0x2f; // "/".codeUnitAt(0)
+  static const int EQUALS = 0x3d; // "=".codeUnitAt(0)
+  static const int OR = 0x7c; // "|".codeUnitAt(0)
+  static const int CARET = 0x5e; // "^".codeUnitAt(0)
+  static const int DOLLAR = 0x24; // "\$".codeUnitAt(0)
+  static const int LESS = 0x3c; // "<".codeUnitAt(0)
+  static const int BANG = 0x21; // "!".codeUnitAt(0)
+  static const int MINUS = 0x2d; // "-".codeUnitAt(0)
+  static const int BACKSLASH = 0x5c; // "\".codeUnitAt(0)
+  static const int AMPERSAND = 0x26; // "&".codeUnitAt(0)
+}
diff --git a/pkg/csslib/lib/src/tree.dart b/pkg/csslib/lib/src/tree.dart
new file mode 100644
index 0000000..e8411d3
--- /dev/null
+++ b/pkg/csslib/lib/src/tree.dart
@@ -0,0 +1,1054 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.visitor;
+
+/////////////////////////////////////////////////////////////////////////
+// CSS specific types:
+/////////////////////////////////////////////////////////////////////////
+
+class Identifier extends TreeNode {
+  String name;
+
+  Identifier(this.name, Span span): super(span);
+
+  visit(VisitorBase visitor) => visitor.visitIdentifier(this);
+
+  String toString() => name;
+}
+
+class Wildcard extends TreeNode {
+  Wildcard(Span span): super(span);
+  visit(VisitorBase visitor) => visitor.visitWildcard(this);
+}
+
+class ThisOperator extends TreeNode {
+  ThisOperator(Span span): super(span);
+  visit(VisitorBase visitor) => visitor.visitThisOperator(this);
+}
+
+class Negation extends TreeNode {
+  Negation(Span span): super(span);
+  visit(VisitorBase visitor) => visitor.visitNegation(this);
+}
+
+// /*  ....   */
+class CssComment extends TreeNode {
+  final String comment;
+
+  CssComment(this.comment, Span span): super(span);
+  visit(VisitorBase visitor) => visitor.visitCssComment(this);
+}
+
+// CDO/CDC (Comment Definition Open <!-- and Comment Definition Close -->).
+class CommentDefinition extends CssComment {
+  CommentDefinition(String comment, Span span): super(comment, span);
+  visit(VisitorBase visitor) => visitor.visitCommentDefinition(this);
+}
+
+class SelectorGroup extends TreeNode {
+  List<Selector> _selectors;
+
+  SelectorGroup(this._selectors, Span span): super(span);
+
+  List<Selector> get selectors => _selectors;
+
+  visit(VisitorBase visitor) => visitor.visitSelectorGroup(this);
+}
+
+class Selector extends TreeNode {
+  final List<SimpleSelectorSequence> _simpleSelectorSequences;
+
+  Selector(this._simpleSelectorSequences, Span span) : super(span);
+
+  List<SimpleSelectorSequence> get simpleSelectorSequences =>
+      _simpleSelectorSequences;
+
+  add(SimpleSelectorSequence seq) => _simpleSelectorSequences.add(seq);
+
+  int get length => _simpleSelectorSequences.length;
+
+  visit(VisitorBase visitor) => visitor.visitSelector(this);
+}
+
+class SimpleSelectorSequence extends TreeNode {
+  /** +, >, ~, NONE */
+  final int _combinator;
+  final SimpleSelector _selector;
+
+  SimpleSelectorSequence(this._selector, Span span,
+      [int combinator = TokenKind.COMBINATOR_NONE])
+      : _combinator = combinator, super(span);
+
+  get simpleSelector => _selector;
+
+  bool get isCombinatorNone => _combinator == TokenKind.COMBINATOR_NONE;
+  bool get isCombinatorPlus => _combinator == TokenKind.COMBINATOR_PLUS;
+  bool get isCombinatorGreater => _combinator == TokenKind.COMBINATOR_GREATER;
+  bool get isCombinatorTilde => _combinator == TokenKind.COMBINATOR_TILDE;
+  bool get isCombinatorDescendant =>
+      _combinator == TokenKind.COMBINATOR_DESCENDANT;
+
+  String get _combinatorToString =>
+      isCombinatorDescendant ? ' ' :
+          isCombinatorPlus ? ' + ' :
+              isCombinatorGreater ? ' > ' :
+                  isCombinatorTilde ? ' ~ ' : '';
+
+  visit(VisitorBase visitor) => visitor.visitSimpleSelectorSequence(this);
+}
+
+/* All other selectors (element, #id, .class, attribute, pseudo, negation,
+ * namespace, *) are derived from this selector.
+ */
+class SimpleSelector extends TreeNode {
+  final _name;
+
+  SimpleSelector(this._name, Span span) : super(span);
+
+  // Name can be an Identifier or WildCard we'll return either the name or '*'.
+  String get name => isWildcard ? '*' : isThis ? '&' : _name.name;
+
+  bool get isWildcard => _name is Wildcard;
+
+  bool get isThis => _name is ThisOperator;
+
+  visit(VisitorBase visitor) => visitor.visitSimpleSelector(this);
+}
+
+// element name
+class ElementSelector extends SimpleSelector {
+  ElementSelector(name, Span span) : super(name, span);
+  visit(VisitorBase visitor) => visitor.visitElementSelector(this);
+}
+
+// namespace|element
+class NamespaceSelector extends SimpleSelector {
+  final _namespace;           // null, Wildcard or Identifier
+
+  NamespaceSelector(this._namespace, var name, Span span) : super(name, span);
+
+  String get namespace =>
+      _namespace is Wildcard ? '*' : _namespace == null ? '' : _namespace.name;
+
+  bool get isNamespaceWildcard => _namespace is Wildcard;
+
+  SimpleSelector get nameAsSimpleSelector => _name;
+
+  visit(VisitorBase visitor) => visitor.visitNamespaceSelector(this);
+}
+
+// [attr op value]
+class AttributeSelector extends SimpleSelector {
+  final int _op;
+  final _value;
+
+  AttributeSelector(Identifier name, this._op, this._value,
+      Span span) : super(name, span);
+
+  String matchOperator() {
+    switch (_op) {
+    case TokenKind.EQUALS:
+      return '=';
+    case TokenKind.INCLUDES:
+      return '~=';
+    case TokenKind.DASH_MATCH:
+      return '|=';
+    case TokenKind.PREFIX_MATCH:
+      return '^=';
+    case TokenKind.SUFFIX_MATCH:
+      return '\$=';
+    case TokenKind.SUBSTRING_MATCH:
+      return '*=';
+    case TokenKind.NO_MATCH:
+      return '';
+    }
+  }
+
+  // Return the TokenKind for operator used by visitAttributeSelector.
+  String matchOperatorAsTokenString() {
+    switch (_op) {
+    case TokenKind.EQUALS:
+      return 'EQUALS';
+    case TokenKind.INCLUDES:
+      return 'INCLUDES';
+    case TokenKind.DASH_MATCH:
+      return 'DASH_MATCH';
+    case TokenKind.PREFIX_MATCH:
+      return 'PREFIX_MATCH';
+    case TokenKind.SUFFIX_MATCH:
+      return 'SUFFIX_MATCH';
+    case TokenKind.SUBSTRING_MATCH:
+      return 'SUBSTRING_MATCH';
+    }
+  }
+
+  String valueToString() {
+    if (_value != null) {
+      if (_value is Identifier) {
+        return _value.name;
+      } else {
+        return '"${_value}"';
+      }
+    } else {
+      return '';
+    }
+  }
+
+  visit(VisitorBase visitor) => visitor.visitAttributeSelector(this);
+}
+
+// #id
+class IdSelector extends SimpleSelector {
+  IdSelector(Identifier name, Span span) : super(name, span);
+  visit(VisitorBase visitor) => visitor.visitIdSelector(this);
+}
+
+// .class
+class ClassSelector extends SimpleSelector {
+  ClassSelector(Identifier name, Span span) : super(name, span);
+  visit(VisitorBase visitor) => visitor.visitClassSelector(this);
+}
+
+// :pseudoClass
+class PseudoClassSelector extends SimpleSelector {
+  PseudoClassSelector(Identifier name, Span span) : super(name, span);
+  visit(VisitorBase visitor) => visitor.visitPseudoClassSelector(this);
+}
+
+// ::pseudoElement
+class PseudoElementSelector extends SimpleSelector {
+  PseudoElementSelector(Identifier name, Span span) : super(name, span);
+  visit(VisitorBase visitor) => visitor.visitPseudoElementSelector(this);
+}
+
+// :pseudoClassFunction(expression)
+class PseudoClassFunctionSelector extends PseudoClassSelector {
+  SelectorExpression expression;
+
+  PseudoClassFunctionSelector(Identifier name, this.expression, Span span)
+      : super(name, span);
+  visit(VisitorBase visitor) => visitor.visitPseudoClassFunctionSelector(this);
+}
+
+// ::pseudoElementFunction(expression)
+class PseudoElementFunctionSelector extends PseudoElementSelector {
+  SelectorExpression expression;
+
+  PseudoElementFunctionSelector(Identifier name, this.expression, Span span)
+      : super(name, span);
+  visit(VisitorBase visitor) =>
+      visitor.visitPseudoElementFunctionSelector(this);
+}
+
+class SelectorExpression extends TreeNode {
+  final List<Expression> _expressions = [];
+
+  SelectorExpression(Span span): super(span);
+
+  add(Expression expression) {
+    _expressions.add(expression);
+  }
+
+  List<Expression> get expressions => _expressions;
+
+  visit(VisitorBase visitor) => visitor.visitSelectorExpression(this);
+}
+
+// :NOT(negation_arg)
+class NegationSelector extends SimpleSelector {
+  SimpleSelector negationArg;
+
+  NegationSelector(this.negationArg, Span span)
+      : super(new Negation(span), span);
+
+  visit(VisitorBase visitor) => visitor.visitNegationSelector(this);
+}
+
+class StyleSheet extends TreeNode {
+  /**
+   * Contains charset, ruleset, directives (media, page, etc.), and selectors.
+   */
+  final topLevels;
+
+  StyleSheet(this.topLevels, Span span) : super(span) {
+    for (final node in topLevels) {
+      assert(node is TopLevelProduction || node is Directive);
+    }
+  }
+
+  /** Selectors only in this tree. */
+  StyleSheet.selector(this.topLevels, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitStyleSheet(this);
+}
+
+class TopLevelProduction extends TreeNode {
+  TopLevelProduction(Span span) : super(span);
+  visit(VisitorBase visitor) => visitor.visitTopLevelProduction(this);
+}
+
+class RuleSet extends TopLevelProduction {
+  final SelectorGroup _selectorGroup;
+  final DeclarationGroup _declarationGroup;
+
+  RuleSet(this._selectorGroup, this._declarationGroup, Span span) : super(span);
+
+  SelectorGroup get selectorGroup => _selectorGroup;
+  DeclarationGroup get declarationGroup => _declarationGroup;
+
+  visit(VisitorBase visitor) => visitor.visitRuleSet(this);
+}
+
+class Directive extends TreeNode {
+  Directive(Span span) : super(span);
+
+  bool get isBuiltIn => true;       // Known CSS directive?
+  bool get isExtension => false;    // SCSS extension?
+
+  visit(VisitorBase visitor) => visitor.visitDirective(this);
+}
+
+class ImportDirective extends Directive {
+  /** import name specified. */
+  final String import;
+
+  /** Any media queries for this import. */
+  final List<MediaQuery> mediaQueries;
+
+  ImportDirective(this.import, this.mediaQueries, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitImportDirective(this);
+}
+
+/**
+ *  MediaExpression grammar:
+ *    '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+ */
+class MediaExpression extends TreeNode {
+  final bool andOperator;
+  final Identifier _mediaFeature;
+  final Expressions exprs;
+
+  MediaExpression(this.andOperator, this._mediaFeature, this.exprs, Span span)
+      : super(span);
+
+  String get mediaFeature => _mediaFeature.name;
+
+  visit(VisitorBase visitor) => visitor.visitMediaExpression(this);
+}
+
+/**
+ * MediaQuery grammar:
+ *    : [ONLY | NOT]? S* media_type S* [ AND S* media_expression ]*
+ *    | media_expression [ AND S* media_expression ]*
+ *   media_type
+ *    : IDENT
+ *   media_expression
+ *    : '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+ *   media_feature
+ *    : IDENT
+ */
+class MediaQuery extends TreeNode {
+  /** not, only or no operator. */
+  final int _mediaUnary;
+  final Identifier _mediaType;
+  final List<MediaExpression> expressions;
+
+  MediaQuery(this._mediaUnary, this._mediaType, this.expressions, Span span)
+      : super(span);
+
+  bool get hasMediaType => _mediaType != null;
+  String get mediaType => _mediaType.name;
+
+  bool get hasUnary => _mediaUnary != -1;
+  String get unary =>
+      TokenKind.idToValue(TokenKind.MEDIA_OPERATORS, _mediaUnary).toUpperCase();
+
+  visit(VisitorBase visitor) => visitor.visitMediaQuery(this);
+}
+
+class MediaDirective extends Directive {
+  List<MediaQuery> mediaQueries;
+  List<RuleSet> rulesets;
+
+  MediaDirective(this.mediaQueries, this.rulesets, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitMediaDirective(this);
+}
+
+class HostDirective extends Directive {
+  List<RuleSet> rulesets;
+
+  HostDirective(this.rulesets, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitHostDirective(this);
+}
+
+class PageDirective extends Directive {
+  final String _ident;
+  final String _pseudoPage;
+  List<DeclarationGroup> _declsMargin;
+
+  PageDirective(this._ident, this._pseudoPage, this._declsMargin,
+      Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitPageDirective(this);
+
+  bool get hasIdent => _ident != null && _ident.length > 0;
+  bool get hasPseudoPage => _pseudoPage != null && _pseudoPage.length > 0;
+}
+
+class CharsetDirective extends Directive {
+  final String charEncoding;
+
+  CharsetDirective(this.charEncoding, Span span) : super(span);
+  visit(VisitorBase visitor) => visitor.visitCharsetDirective(this);
+}
+
+class KeyFrameDirective extends Directive {
+  /*
+   * Either @keyframe or keyframe prefixed with @-webkit-, @-moz-, @-ms-, @-o-.
+   */
+  final int _keyframeName;
+  final _name;
+  final List<KeyFrameBlock> _blocks;
+
+  KeyFrameDirective(this._keyframeName, this._name, Span span)
+      : _blocks = [], super(span);
+
+  add(KeyFrameBlock block) {
+    _blocks.add(block);
+  }
+
+  String get keyFrameName {
+    switch (_keyframeName) {
+      case TokenKind.DIRECTIVE_KEYFRAMES:
+      case TokenKind.DIRECTIVE_MS_KEYFRAMES:
+        return '@keyframes';
+      case TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES: return '@-webkit-keyframes';
+      case TokenKind.DIRECTIVE_MOZ_KEYFRAMES: return '@-moz-keyframes';
+      case TokenKind.DIRECTIVE_O_KEYFRAMES: return '@-o-keyframes';
+    }
+  }
+
+  String get name => _name;
+
+  visit(VisitorBase visitor) => visitor.visitKeyFrameDirective(this);
+}
+
+class KeyFrameBlock extends Expression {
+  final Expressions _blockSelectors;
+  final DeclarationGroup _declarations;
+
+  KeyFrameBlock(this._blockSelectors, this._declarations, Span span)
+      : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitKeyFrameBlock(this);
+}
+
+class FontFaceDirective extends Directive {
+  final DeclarationGroup _declarations;
+
+  FontFaceDirective(this._declarations, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitFontFaceDirective(this);
+}
+
+class StyletDirective extends Directive {
+  final String _dartClassName;
+  final List<RuleSet> _rulesets;
+
+  StyletDirective(this._dartClassName, this._rulesets, Span span) : super(span);
+
+  bool get isBuiltIn => false;
+  bool get isExtension => true;
+
+  String get dartClassName => _dartClassName;
+  List<RuleSet> get rulesets => _rulesets;
+
+  visit(VisitorBase visitor) => visitor.visitStyletDirective(this);
+}
+
+class NamespaceDirective extends Directive {
+  /** Namespace prefix. */
+  final String _prefix;
+
+  /** URI associated with this namespace. */
+  final String _uri;
+
+  NamespaceDirective(this._prefix, this._uri, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitNamespaceDirective(this);
+
+  String get prefix => _prefix.length > 0 ? '$_prefix ' : '';
+}
+
+/** To support Less syntax @name: expression */
+class VarDefinitionDirective extends Directive {
+  final VarDefinition def;
+
+  VarDefinitionDirective(this.def, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitVarDefinitionDirective(this);
+}
+
+class Declaration extends TreeNode {
+  final Identifier _property;
+  final Expression _expression;
+  /** Style exposed to Dart. */
+  var _dart;
+  final bool important;
+
+  /**
+   * IE CSS hacks that can only be read by a particular IE version.
+   *   7 implies IE 7 or older property (e.g., *background: blue;)
+   *   Note:  IE 8 or older property (e.g., background: green\9;) is handled
+   *          by IE8Term in declaration expression handling.
+   *   Note:  IE 6 only property with a leading underscore is a valid IDENT
+   *          since an ident can start with underscore (e.g., _background: red;)
+   */
+  final bool isIE7;
+
+  Declaration(this._property, this._expression, this._dart, Span span,
+              {important: false, ie7: false})
+      : this.important = important, this.isIE7 = ie7, super(span);
+
+  String get property => isIE7 ? '*${_property.name}' : _property.name;
+  Expression get expression => _expression;
+
+  bool get hasDartStyle => _dart != null;
+  get dartStyle => _dart;
+  set dartStyle(dStyle) {
+    _dart = dStyle;
+  }
+
+  visit(VisitorBase visitor) => visitor.visitDeclaration(this);
+}
+
+// TODO(terry): Consider 2 kinds of VarDefinitions static at top-level and
+//              dynamic when in a declaration.  Currently, Less syntax
+//              '@foo: expression' and 'var-foo: expression' in a declaration
+//              are statically resolved. Better solution, if @foo or var-foo
+//              are top-level are then statically resolved and var-foo in a
+//              declaration group (surrounded by a selector) would be dynamic.
+class VarDefinition extends Declaration {
+  VarDefinition(Identifier definedName, Expression expr, Span span)
+      : super(definedName, expr, null, span);
+
+  String get definedName => _property.name;
+
+  set dartStyle(dStyle) { }
+
+  visit(VisitorBase visitor) => visitor.visitVarDefinition(this);
+}
+
+class DeclarationGroup extends TreeNode {
+  /** Can be either Declaration or RuleSet (if nested selector). */
+  final List _declarations;
+
+  DeclarationGroup(this._declarations, Span span) : super(span);
+
+  List get declarations => _declarations;
+
+  visit(VisitorBase visitor) => visitor.visitDeclarationGroup(this);
+}
+
+class MarginGroup extends DeclarationGroup {
+  final int margin_sym;       // TokenType for for @margin sym.
+
+  MarginGroup(this.margin_sym, List<Declaration> decls, Span span)
+      : super(decls, span);
+  visit(VisitorBase visitor) => visitor.visitMarginGroup(this);
+}
+
+class VarUsage extends Expression {
+  final String name;
+  final List<Expression> defaultValues;
+
+  VarUsage(this.name, this.defaultValues, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitVarUsage(this);
+}
+
+class OperatorSlash extends Expression {
+  OperatorSlash(Span span) : super(span);
+  visit(VisitorBase visitor) => visitor.visitOperatorSlash(this);
+}
+
+class OperatorComma extends Expression {
+  OperatorComma(Span span) : super(span);
+  visit(VisitorBase visitor) => visitor.visitOperatorComma(this);
+}
+
+class OperatorPlus extends Expression {
+  OperatorPlus(Span span) : super(span);
+  visit(VisitorBase visitor) => visitor.visitOperatorPlus(this);
+}
+
+class OperatorMinus extends Expression {
+  OperatorMinus(Span span) : super(span);
+  visit(VisitorBase visitor) => visitor.visitOperatorMinus(this);
+}
+
+class UnicodeRangeTerm extends Expression {
+  final String first;
+  final String second;
+
+  UnicodeRangeTerm(this.first, this.second, Span span) : super(span);
+
+  bool get hasSecond => second != null;
+
+  visit(VisitorBase visitor) => visitor.visitUnicodeRangeTerm(this);
+}
+
+class LiteralTerm extends Expression {
+  // TODO(terry): value and text fields can be made final once all CSS resources
+  //              are copied/symlink'd in the build tool and UriVisitor in
+  //              web_ui is removed.
+  var value;
+  String text;
+
+  LiteralTerm(this.value, this.text, Span span) : super(span);
+
+  visit(VisitorBase visitor) => visitor.visitLiteralTerm(this);
+}
+
+class NumberTerm extends LiteralTerm {
+  NumberTerm(value, String t, Span span) : super(value, t, span);
+  visit(VisitorBase visitor) => visitor.visitNumberTerm(this);
+}
+
+class UnitTerm extends LiteralTerm {
+  final int _unit;
+
+  UnitTerm(value, String t, Span span, this._unit) : super(value, t, span);
+
+  int get unit => _unit;
+
+  visit(VisitorBase visitor) => visitor.visitUnitTerm(this);
+
+  String unitToString() => TokenKind.unitToString(_unit);
+
+  String toString() => '$text${unitToString()}';
+}
+
+class LengthTerm extends UnitTerm {
+  LengthTerm(value, String t, Span span,
+      [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(this._unit == TokenKind.UNIT_LENGTH_PX ||
+        this._unit == TokenKind.UNIT_LENGTH_CM ||
+        this._unit == TokenKind.UNIT_LENGTH_MM ||
+        this._unit == TokenKind.UNIT_LENGTH_IN ||
+        this._unit == TokenKind.UNIT_LENGTH_PT ||
+        this._unit == TokenKind.UNIT_LENGTH_PC);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitLengthTerm(this);
+}
+
+class PercentageTerm extends LiteralTerm {
+  PercentageTerm(value, String t, Span span) : super(value, t, span);
+  visit(VisitorBase visitor) => visitor.visitPercentageTerm(this);
+}
+
+class EmTerm extends LiteralTerm {
+  EmTerm(value, String t, Span span) : super(value, t, span);
+  visit(VisitorBase visitor) => visitor.visitEmTerm(this);
+}
+
+class ExTerm extends LiteralTerm {
+  ExTerm(value, String t, Span span) : super(value, t, span);
+  visit(VisitorBase visitor) => visitor.visitExTerm(this);
+}
+
+class AngleTerm extends UnitTerm {
+  AngleTerm(var value, String t, Span span,
+    [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(this._unit == TokenKind.UNIT_ANGLE_DEG ||
+        this._unit == TokenKind.UNIT_ANGLE_RAD ||
+        this._unit == TokenKind.UNIT_ANGLE_GRAD ||
+        this._unit == TokenKind.UNIT_ANGLE_TURN);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitAngleTerm(this);
+}
+
+class TimeTerm extends UnitTerm {
+  TimeTerm(var value, String t, Span span,
+    [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(this._unit == TokenKind.UNIT_ANGLE_DEG ||
+        this._unit == TokenKind.UNIT_TIME_MS ||
+        this._unit == TokenKind.UNIT_TIME_S);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitTimeTerm(this);
+}
+
+class FreqTerm extends UnitTerm {
+  FreqTerm(var value, String t, Span span,
+    [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(_unit == TokenKind.UNIT_FREQ_HZ || _unit == TokenKind.UNIT_FREQ_KHZ);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitFreqTerm(this);
+}
+
+class FractionTerm extends LiteralTerm {
+  FractionTerm(var value, String t, Span span) : super(value, t, span);
+
+  visit(VisitorBase visitor) => visitor.visitFractionTerm(this);
+}
+
+class UriTerm extends LiteralTerm {
+  UriTerm(String value, Span span) : super(value, value, span);
+
+  visit(VisitorBase visitor) => visitor.visitUriTerm(this);
+}
+
+class ResolutionTerm extends UnitTerm {
+  ResolutionTerm(var value, String t, Span span,
+    [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(_unit == TokenKind.UNIT_RESOLUTION_DPI ||
+        _unit == TokenKind.UNIT_RESOLUTION_DPCM ||
+        _unit == TokenKind.UNIT_RESOLUTION_DPPX);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitResolutionTerm(this);
+}
+
+class ChTerm extends UnitTerm {
+  ChTerm(var value, String t, Span span,
+    [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(_unit == TokenKind.UNIT_CH);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitChTerm(this);
+}
+
+class RemTerm extends UnitTerm {
+  RemTerm(var value, String t, Span span,
+    [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(_unit == TokenKind.UNIT_REM);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitRemTerm(this);
+}
+
+class ViewportTerm extends UnitTerm {
+  ViewportTerm(var value, String t, Span span,
+    [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) {
+    assert(_unit == TokenKind.UNIT_VIEWPORT_VW ||
+        _unit == TokenKind.UNIT_VIEWPORT_VH ||
+        _unit == TokenKind.UNIT_VIEWPORT_VMIN ||
+        _unit == TokenKind.UNIT_VIEWPORT_VMAX);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitViewportTerm(this);
+}
+
+/** Type to signal a bad hex value for HexColorTerm.value. */
+class BAD_HEX_VALUE { }
+
+class HexColorTerm extends LiteralTerm {
+  HexColorTerm(var value, String t, Span span) : super(value, t, span);
+
+  visit(VisitorBase visitor) => visitor.visitHexColorTerm(this);
+}
+
+class FunctionTerm extends LiteralTerm {
+  final Expressions _params;
+
+  FunctionTerm(var value, String t, this._params, Span span)
+      : super(value, t, span);
+
+  visit(VisitorBase visitor) => visitor.visitFunctionTerm(this);
+}
+
+/**
+ * A "\9" was encountered at the end of the expression and before a semi-colon.
+ * This is an IE trick to ignore a property or value except by IE 8 and older
+ * browsers.
+ */
+class IE8Term extends LiteralTerm {
+  IE8Term(Span span) : super('\\9', '\\9', span);
+  visit(VisitorBase visitor) => visitor.visitIE8Term(this);
+}
+
+class GroupTerm extends Expression {
+  final List<LiteralTerm> _terms;
+
+  GroupTerm(Span span) : _terms =  [], super(span);
+
+  add(LiteralTerm term) {
+    _terms.add(term);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitGroupTerm(this);
+}
+
+class ItemTerm extends NumberTerm {
+  ItemTerm(var value, String t, Span span) : super(value, t, span);
+
+  visit(VisitorBase visitor) => visitor.visitItemTerm(this);
+}
+
+class Expressions extends Expression {
+  final List<Expression> expressions = [];
+
+  Expressions(Span span): super(span);
+
+  add(Expression expression) {
+    expressions.add(expression);
+  }
+
+  visit(VisitorBase visitor) => visitor.visitExpressions(this);
+}
+
+class BinaryExpression extends Expression {
+  final Token op;
+  final Expression x;
+  final Expression y;
+
+  BinaryExpression(this.op, this.x, this.y, Span span): super(span);
+
+  visit(VisitorBase visitor) => visitor.visitBinaryExpression(this);
+}
+
+class UnaryExpression extends Expression {
+  final Token op;
+  final Expression self;
+
+  UnaryExpression(this.op, this.self, Span span): super(span);
+
+  visit(VisitorBase visitor) => visitor.visitUnaryExpression(this);
+}
+
+abstract class DartStyleExpression extends TreeNode {
+  static final int unknownType = 0;
+  static final int fontStyle = 1;
+  static final int marginStyle = 2;
+  static final int borderStyle = 3;
+  static final int paddingStyle = 4;
+  static final int heightStyle = 5;
+  static final int widthStyle = 6;
+
+  final int _styleType;
+  int priority;
+
+  DartStyleExpression(this._styleType, Span span) : super(span);
+
+  /*
+   * Merges give 2 DartStyleExpression (or derived from DartStyleExpression,
+   * e.g., FontExpression, etc.) will merge if the two expressions are of the
+   * same property name (implies same exact type e.g, FontExpression).
+   */
+  merged(DartStyleExpression newDartExpr);
+
+  bool get isUnknown => _styleType == 0 || _styleType == null;
+  bool get isFont => _styleType == fontStyle;
+  bool get isMargin => _styleType == marginStyle;
+  bool get isBorder => _styleType == borderStyle;
+  bool get isPadding => _styleType == paddingStyle;
+  bool get isHeight => _styleType == heightStyle;
+  bool get isWidth => _styleType == widthStyle;
+  bool get isBoxExpression => isMargin || isBorder || isPadding;
+
+  bool isSame(DartStyleExpression other) => this._styleType == other._styleType;
+
+  visit(VisitorBase visitor) => visitor.visitDartStyleExpression(this);
+}
+
+class FontExpression extends DartStyleExpression {
+  Font font;
+
+  //   font-style font-variant font-weight font-size/line-height font-family
+  FontExpression(Span span, {var size, List<String>family,
+      int weight, String style, String variant, LineHeight lineHeight})
+      : super(DartStyleExpression.fontStyle, span) {
+    // TODO(terry): Only px/pt for now need to handle all possible units to
+    //              support calc expressions on units.
+    font = new Font(size : size is LengthTerm ? size.value : size,
+        family: family, weight: weight, style: style, variant: variant,
+        lineHeight: lineHeight);
+  }
+
+  merged(FontExpression newFontExpr) {
+    if (this.isFont && newFontExpr.isFont) {
+      return new FontExpression.merge(this, newFontExpr);
+    }
+
+    return null;
+  }
+
+  /**
+   * Merge the two FontExpression and return the result.
+   */
+  factory FontExpression.merge(FontExpression x, FontExpression y) {
+    return new FontExpression._merge(x, y, y.span);
+  }
+
+  FontExpression._merge(FontExpression x, FontExpression y, Span span)
+      : super(DartStyleExpression.fontStyle, span),
+        font = new Font.merge(x.font, y.font);
+
+  visit(VisitorBase visitor) => visitor.visitFontExpression(this);
+}
+
+abstract class BoxExpression extends DartStyleExpression {
+  final BoxEdge box;
+
+  BoxExpression(int styleType, Span span, this.box)
+      : super(styleType, span);
+
+  /*
+   * Merges give 2 DartStyleExpression (or derived from DartStyleExpression,
+   * e.g., FontExpression, etc.) will merge if the two expressions are of the
+   * same property name (implies same exact type e.g, FontExpression).
+   */
+  merged(BoxExpression newDartExpr);
+
+  visit(VisitorBase visitor) => visitor.visitBoxExpression(this);
+
+  String get formattedBoxEdge {
+    if (box.top == box.left && box.top == box.bottom &&
+        box.top== box.right) {
+      return '.uniform(${box.top})';
+    } else {
+      var left = box.left == null ? 0 : box.left;
+      var top = box.top == null ? 0 : box.top;
+      var right = box.right == null ? 0 : box.right;
+      var bottom = box.bottom == null ? 0 : box.bottom;
+      return '.clockwiseFromTop($top,$right,$bottom,$left)';
+    }
+  }
+}
+
+class MarginExpression extends BoxExpression {
+  // TODO(terry): Does auto for margin need to be exposed to Dart UI framework?
+  /** Margin expression ripped apart. */
+  MarginExpression(Span span, {num top, num right, num bottom, num left})
+      : super(DartStyleExpression.marginStyle, span,
+              new BoxEdge(left, top, right, bottom));
+
+  MarginExpression.boxEdge(Span span, BoxEdge box)
+      : super(DartStyleExpression.marginStyle, span, box);
+
+  merged(MarginExpression newMarginExpr) {
+    if (this.isMargin && newMarginExpr.isMargin) {
+      return new MarginExpression.merge(this, newMarginExpr);
+    }
+
+    return null;
+  }
+
+  /**
+   * Merge the two MarginExpressions and return the result.
+   */
+  factory MarginExpression.merge(MarginExpression x, MarginExpression y) {
+    return new MarginExpression._merge(x, y, y.span);
+  }
+
+  MarginExpression._merge(MarginExpression x, MarginExpression y, Span span)
+      : super(x._styleType, span, new BoxEdge.merge(x.box, y.box));
+
+  visit(VisitorBase visitor) => visitor.visitMarginExpression(this);
+}
+
+class BorderExpression extends BoxExpression {
+  /** Border expression ripped apart. */
+  BorderExpression(Span span, {num top, num right, num bottom, num left})
+      : super(DartStyleExpression.borderStyle, span,
+              new BoxEdge(left, top, right, bottom));
+
+  BorderExpression.boxEdge(Span span, BoxEdge box)
+      : super(DartStyleExpression.borderStyle, span, box);
+
+  merged(BorderExpression newBorderExpr) {
+    if (this.isBorder && newBorderExpr.isBorder) {
+      return new BorderExpression.merge(this, newBorderExpr);
+    }
+
+    return null;
+  }
+
+  /**
+   * Merge the two BorderExpression and return the result.
+   */
+  factory BorderExpression.merge(BorderExpression x, BorderExpression y) {
+    return new BorderExpression._merge(x, y, y.span);
+  }
+
+  BorderExpression._merge(BorderExpression x, BorderExpression y,
+      Span span)
+      : super(DartStyleExpression.borderStyle, span,
+              new BoxEdge.merge(x.box, y.box));
+
+  visit(VisitorBase visitor) => visitor.visitBorderExpression(this);
+}
+
+class HeightExpression extends DartStyleExpression {
+  final height;
+
+  HeightExpression(Span span, this.height)
+      : super(DartStyleExpression.heightStyle, span);
+
+  merged(HeightExpression newHeightExpr) {
+    if (this.isHeight && newHeightExpr.isHeight) {
+      return newHeightExpr;
+    }
+
+    return null;
+  }
+
+  visit(VisitorBase visitor) => visitor.visitHeightExpression(this);
+}
+
+class WidthExpression extends DartStyleExpression {
+  final width;
+
+  WidthExpression(Span span, this.width)
+      : super(DartStyleExpression.widthStyle, span);
+
+  merged(WidthExpression newWidthExpr) {
+    if (this.isWidth && newWidthExpr.isWidth) {
+      return newWidthExpr;
+    }
+
+    return null;
+  }
+
+  visit(VisitorBase visitor) => visitor.visitWidthExpression(this);
+}
+
+class PaddingExpression extends BoxExpression {
+  /** Padding expression ripped apart. */
+  PaddingExpression(Span span, {num top, num right, num bottom, num left})
+      : super(DartStyleExpression.paddingStyle, span,
+              new BoxEdge(left, top, right, bottom));
+
+  PaddingExpression.boxEdge(Span span, BoxEdge box)
+      : super(DartStyleExpression.paddingStyle, span, box);
+
+  merged(PaddingExpression newPaddingExpr) {
+    if (this.isPadding && newPaddingExpr.isPadding) {
+      return new PaddingExpression.merge(this, newPaddingExpr);
+    }
+
+    return null;
+  }
+
+  /**
+   * Merge the two PaddingExpression and return the result.
+   */
+  factory PaddingExpression.merge(PaddingExpression x, PaddingExpression y) {
+    return new PaddingExpression._merge(x, y, y.span);
+  }
+
+  PaddingExpression._merge(PaddingExpression x, PaddingExpression y, Span span)
+      : super(DartStyleExpression.paddingStyle, span,
+            new BoxEdge.merge(x.box, y.box));
+
+  visit(VisitorBase visitor) => visitor.visitPaddingExpression(this);
+}
diff --git a/pkg/csslib/lib/src/tree_base.dart b/pkg/csslib/lib/src/tree_base.dart
new file mode 100644
index 0000000..31411d6
--- /dev/null
+++ b/pkg/csslib/lib/src/tree_base.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.visitor;
+
+/**
+ * The base type for all nodes in a CSS abstract syntax tree.
+ */
+abstract class TreeNode {
+  /** The source code this [TreeNode] represents. */
+  Span span;
+
+  TreeNode(this.span) {}
+
+  /** Classic double-dispatch visitor for implementing passes. */
+  visit(VisitorBase visitor);
+
+  /** A multiline string showing the node and its children. */
+  String toDebugString() {
+    var to = new TreeOutput();
+    var tp = new _TreePrinter(to, true);
+    this.visit(tp);
+    return to.buf.toString();
+  }
+}
+
+/** The base type for expressions. */
+abstract class Expression extends TreeNode {
+  Expression(Span span): super(span);
+}
+
+/** Simple class to provide a textual dump of trees for debugging. */
+class TreeOutput {
+  int depth = 0;
+  final StringBuffer buf = new StringBuffer();
+  var printer;
+
+  void write(String s) {
+    for (int i=0; i < depth; i++) {
+      buf.write(' ');
+    }
+    buf.write(s);
+  }
+
+  void writeln(String s) {
+    write(s);
+    buf.write('\n');
+  }
+
+  void heading(String name, [span]) {
+    write(name);
+    if (span != null) {
+      buf.write('  (${span.getLocationMessage('')})');
+    }
+    buf.write('\n');
+  }
+
+  String toValue(value) {
+    if (value == null) return 'null';
+    else if (value is Identifier) return value.name;
+    else return value.toString();
+  }
+
+  void writeNode(String label, TreeNode node) {
+    write('${label}: ');
+    depth += 1;
+    if (node != null) node.visit(printer);
+    else writeln('null');
+    depth -= 1;
+  }
+
+  void writeValue(String label, value) {
+    var v = toValue(value);
+    writeln('${label}: ${v}');
+  }
+
+  void writeList(String label, List list) {
+    write('${label}: ');
+    if (list == null) {
+      buf.write('null');
+      buf.write('\n');
+    } else {
+      for (var item in list) {
+        buf.write(item.toString());
+        buf.write(', ');
+      }
+      buf.write('\n');
+    }
+  }
+
+  void writeNodeList(String label, List list) {
+    writeln('${label} [');
+    if (list != null) {
+      depth += 1;
+      for (var node in list) {
+        if (node != null) {
+          node.visit(printer);
+        } else {
+          writeln('null');
+        }
+      }
+      depth -= 1;
+      writeln(']');
+    }
+  }
+
+  String toString() => buf.toString();
+}
diff --git a/pkg/csslib/lib/src/tree_printer.dart b/pkg/csslib/lib/src/tree_printer.dart
new file mode 100644
index 0000000..24cca64
--- /dev/null
+++ b/pkg/csslib/lib/src/tree_printer.dart
@@ -0,0 +1,512 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.visitor;
+
+// TODO(terry): Enable class for debug only; when conditional imports enabled.
+
+/** Helper function to dump the CSS AST. */
+String treeToDebugString(styleSheet, [bool useSpan = false]) {
+  var to = new TreeOutput();
+  new _TreePrinter(to, useSpan)..visitTree(styleSheet);
+  return to.toString();
+}
+
+/** Tree dump for debug output of the CSS AST. */
+class _TreePrinter extends Visitor {
+  var output;
+  final bool useSpan;
+  _TreePrinter(this.output, this.useSpan) { output.printer = this; }
+
+  void visitTree(tree) => visitStylesheet(tree);
+
+  void heading(String heading, node) {
+    if (useSpan) {
+      output.heading(heading, node.span);
+    } else {
+      output.heading(heading);
+    }
+  }
+
+  void visitStylesheet(StyleSheet node) {
+    heading('Stylesheet', node);
+    output.depth++;
+    super.visitStyleSheet(node);
+    output.depth--;
+  }
+
+  void visitTopLevelProduction(TopLevelProduction node) {
+    heading('TopLevelProduction', node);
+  }
+
+  void visitDirective(Directive node) {
+    heading('Directive', node);
+  }
+
+  void visitCssComment(CssComment node) {
+    heading('Comment', node);
+    output.depth++;
+    output.writeValue('comment value', node.comment);
+    output.depth--;
+  }
+
+  void visitCommentDefinition(CommentDefinition node) {
+    heading('CommentDefinition (CDO/CDC)', node);
+    output.depth++;
+    output.writeValue('comment value', node.comment);
+    output.depth--;
+  }
+
+  void visitMediaExpression(MediaExpression node) {
+    heading('MediaExpression', node);
+    output.writeValue('feature', node.mediaFeature);
+    if (node.andOperator) output.writeValue('AND operator', '');
+    visitExpressions(node.exprs);
+  }
+
+  void visitMediaQueries(MediaQuery query) {
+    output.headeing('MediaQueries');
+    output.writeValue('unary', query.unary);
+    output.writeValue('media type', query.mediaType);
+    output.writeNodeList('media expressions', query.expressions);
+  }
+
+  void visitMediaDirective(MediaDirective node) {
+    heading('MediaDirective', node);
+    output.depth++;
+    output.writeNodeList('media queries', node.mediaQueries);
+    output.writeNodeList('rule sets', node.rulesets);
+    super.visitMediaDirective(node);
+    output.depth--;
+  }
+
+  void visitPageDirective(PageDirective node) {
+    heading('PageDirective', node);
+    output.depth++;
+    output.writeValue('pseudo page', node._pseudoPage);
+    super.visitPageDirective(node);
+    output.depth;
+  }
+
+  void visitCharsetDirective(CharsetDirective node) {
+    heading('Charset Directive', node);
+    output.writeValue('charset encoding', node.charEncoding);
+  }
+
+  void visitImportDirective(ImportDirective node) {
+    heading('ImportDirective', node);
+    output.depth++;
+    output.writeValue('import', node.import);
+    super.visitImportDirective(node);
+    output.writeNodeList('media', node.mediaQueries);
+    output.depth--;
+  }
+
+  void visitKeyFrameDirective(KeyFrameDirective node) {
+    heading('KeyFrameDirective', node);
+    output.depth++;
+    output.writeValue('keyframe', node.keyFrameName);
+    output.writeValue('name', node._name);
+    output.writeNodeList('blocks', node._blocks);
+    output.depth--;
+  }
+
+  void visitKeyFrameBlock(KeyFrameBlock node) {
+    heading('KeyFrameBlock', node);
+    output.depth++;
+    super.visitKeyFrameBlock(node);
+    output.depth--;
+  }
+
+  void visitFontFaceDirective(FontFaceDirective node) {
+    // TODO(terry): To Be Implemented
+  }
+
+  void visitStyletDirective(StyletDirective node) {
+    heading('StyletDirective', node);
+    output.writeValue('dartClassName', node._dartClassName);
+    output.depth++;
+    output.writeNodeList('rulesets', node._rulesets);
+    output.depth--;
+  }
+
+  void visitNamespaceDirective(NamespaceDirective node) {
+    heading('NamespaceDirective', node);
+    output.depth++;
+    output.writeValue('prefix', node._prefix);
+    output.writeValue('uri', node._uri);
+    output.depth--;
+  }
+
+  void visitVarDefinitionDirective(VarDefinitionDirective node) {
+    heading('Less variable definition', node);
+    visitVarDefinition(node.def);
+  }
+
+  void visitRuleSet(RuleSet node) {
+    heading('Ruleset', node);
+    output.depth++;
+    super.visitRuleSet(node);
+    output.depth--;
+  }
+
+  void visitDeclarationGroup(DeclarationGroup node) {
+    heading('DeclarationGroup', node);
+    output.depth++;
+    output.writeNodeList('declarations', node._declarations);
+    output.depth--;
+  }
+
+  void visitMarginGroup(MarginGroup node) {
+    heading('MarginGroup', node);
+    output.depth++;
+    output.writeValue('@directive', node.margin_sym);
+    output.writeNodeList('declarations', node._declarations);
+    output.depth--;
+  }
+
+  void visitDeclaration(Declaration node) {
+    heading('Declaration', node);
+    output.depth++;
+    if (node.isIE7) output.write('IE7 property');
+    output.write('property');
+    super.visitDeclaration(node);
+    output.writeNode('expression', node._expression);
+    if (node.important) {
+      output.writeValue('!important', 'true');
+    }
+    output.depth--;
+  }
+
+  void visitVarDefinition(VarDefinition node) {
+    heading('Var', node);
+    output.depth++;
+    output.write('defintion');
+    super.visitVarDefinition(node);
+    output.writeNode('expression', node._expression);
+    output.depth--;
+  }
+
+  void visitSelectorGroup(SelectorGroup node) {
+    heading('Selector Group', node);
+    output.depth++;
+    output.writeNodeList('selectors', node.selectors);
+    output.depth--;
+  }
+
+  void visitSelector(Selector node) {
+    heading('Selector', node);
+    output.depth++;
+    output.writeNodeList('simpleSelectorsSequences',
+        node._simpleSelectorSequences);
+    output.depth--;
+  }
+
+  void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+    heading('SimpleSelectorSequence', node);
+    output.depth++;
+    if (node.isCombinatorNone) {
+      output.writeValue('combinator', "NONE");
+    } else if (node.isCombinatorDescendant) {
+      output.writeValue('combinator', "descendant");
+    } else if (node.isCombinatorPlus) {
+      output.writeValue('combinator', "+");
+    } else if (node.isCombinatorGreater) {
+      output.writeValue('combinator', ">");
+    } else if (node.isCombinatorTilde) {
+      output.writeValue('combinator', "~");
+    } else {
+      output.writeValue('combinator', "ERROR UNKNOWN");
+    }
+
+    super.visitSimpleSelectorSequence(node);
+
+    output.depth--;
+  }
+
+  void visitNamespaceSelector(NamespaceSelector node) {
+    heading('Namespace Selector', node);
+    output.depth++;
+
+    super.visitNamespaceSelector(node);
+
+    visitSimpleSelector(node.nameAsSimpleSelector);
+    output.depth--;
+  }
+
+  void visitElementSelector(ElementSelector node) {
+    heading('Element Selector', node);
+    output.depth++;
+    super.visitElementSelector(node);
+    output.depth--;
+  }
+
+  void visitAttributeSelector(AttributeSelector node) {
+    heading('AttributeSelector', node);
+    output.depth++;
+    super.visitAttributeSelector(node);
+    String tokenStr = node.matchOperatorAsTokenString();
+    output.writeValue('operator', '${node.matchOperator()} (${tokenStr})');
+    output.writeValue('value', node.valueToString());
+    output.depth--;
+  }
+
+  void visitIdSelector(IdSelector node) {
+    heading('Id Selector', node);
+    output.depth++;
+    super.visitIdSelector(node);
+    output.depth--;
+  }
+
+  void visitClassSelector(ClassSelector node) {
+    heading('Class Selector', node);
+    output.depth++;
+    super.visitClassSelector(node);
+    output.depth--;
+  }
+
+  void visitPseudoClassSelector(PseudoClassSelector node) {
+    heading('Pseudo Class Selector', node);
+    output.depth++;
+    super.visitPseudoClassSelector(node);
+    output.depth--;
+  }
+
+  void visitPseudoElementSelector(PseudoElementSelector node) {
+    heading('Pseudo Element Selector', node);
+    output.depth++;
+    super.visitPseudoElementSelector(node);
+    output.depth--;
+  }
+
+  void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
+    heading('Pseudo Class Function Selector', node);
+    output.depth++;
+    visitSelectorExpression(node.expression);
+    super.visitPseudoClassFunctionSelector(node);
+    output.depth--;
+  }
+
+  void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) {
+    heading('Pseudo Element Function Selector', node);
+    output.depth++;
+    visitSelectorExpression(node.expression);
+    super.visitPseudoElementFunctionSelector(node);
+    output.depth--;
+  }
+
+  void visitSelectorExpression(SelectorExpression node) {
+    heading('Selector Expression', node);
+    output.depth++;
+    output.writeNodeList('expressions', node.expressions);
+    output.depth--;
+  }
+
+  void visitNegationSelector(NegationSelector node) {
+    super.visitNegationSelector(node);
+    output.depth++;
+    heading('Negation Selector', node);
+    output.writeNode('Negation arg', node.negationArg);
+    output.depth--;
+  }
+
+  void visitUnicodeRangeTerm(UnicodeRangeTerm node) {
+    heading('UnicodeRangeTerm', node);
+    output.depth++;
+    output.writeValue('1st value', node.first);
+    output.writeValue('2nd value', node.second);
+    output.depth--;
+  }
+
+  void visitLiteralTerm(LiteralTerm node) {
+    heading('LiteralTerm', node);
+    output.depth++;
+    output.writeValue('value', node.text);
+    output.depth--;
+ }
+
+  void visitHexColorTerm(HexColorTerm node) {
+    heading('HexColorTerm', node);
+    output.depth++;
+    output.writeValue('hex value', node.text);
+    output.writeValue('decimal value', node.value);
+    output.depth--;
+  }
+
+  void visitNumberTerm(NumberTerm node) {
+    heading('NumberTerm', node);
+    output.depth++;
+    output.writeValue('value', node.text);
+    output.depth--;
+  }
+
+  void visitUnitTerm(UnitTerm node) {
+    String unitValue;
+
+    output.depth++;
+    output.writeValue('value', node.text);
+    output.writeValue('unit', node.unitToString());
+    output.depth--;
+  }
+
+  void visitLengthTerm(LengthTerm node) {
+    heading('LengthTerm', node);
+    super.visitLengthTerm(node);
+  }
+
+  void visitPercentageTerm(PercentageTerm node) {
+    heading('PercentageTerm', node);
+    output.depth++;
+    super.visitPercentageTerm(node);
+    output.depth--;
+  }
+
+  void visitEmTerm(EmTerm node) {
+    heading('EmTerm', node);
+    output.depth++;
+    super.visitEmTerm(node);
+    output.depth--;
+  }
+
+  void visitExTerm(ExTerm node) {
+    heading('ExTerm', node);
+    output.depth++;
+    super.visitExTerm(node);
+    output.depth--;
+  }
+
+  void visitAngleTerm(AngleTerm node) {
+    heading('AngleTerm', node);
+    super.visitAngleTerm(node);
+  }
+
+  void visitTimeTerm(TimeTerm node) {
+    heading('TimeTerm', node);
+    super.visitTimeTerm(node);
+  }
+
+  void visitFreqTerm(FreqTerm node) {
+    heading('FreqTerm', node);
+    super.visitFreqTerm(node);
+  }
+
+  void visitFractionTerm(FractionTerm node) {
+    heading('FractionTerm', node);
+    output.depth++;
+    super.visitFractionTerm(node);
+    output.depth--;
+  }
+
+  void visitUriTerm(UriTerm node) {
+    heading('UriTerm', node);
+    output.depth++;
+    super.visitUriTerm(node);
+    output.depth--;
+  }
+
+  void visitFunctionTerm(FunctionTerm node) {
+    heading('FunctionTerm', node);
+    output.depth++;
+    super.visitFunctionTerm(node);
+    output.depth--;
+  }
+
+  void visitGroupTerm(GroupTerm node) {
+    heading('GroupTerm', node);
+    output.depth++;
+    output.writeNodeList('grouped terms', node._terms);
+    output.depth--;
+  }
+
+  void visitItemTerm(ItemTerm node) {
+    heading('ItemTerm', node);
+    super.visitItemTerm(node);
+  }
+
+  void visitIE8Term(IE8Term node) {
+    heading('IE8Term', node);
+    visitLiteralTerm(node);
+  }
+
+  void visitOperatorSlash(OperatorSlash node) {
+    heading('OperatorSlash', node);
+  }
+
+  void visitOperatorComma(OperatorComma node) {
+    heading('OperatorComma', node);
+  }
+
+  void visitOperatorPlus(OperatorPlus node) {
+    heading('OperatorPlus', node);
+  }
+
+  void visitOperatorMinus(OperatorMinus node) {
+    heading('OperatorMinus', node);
+  }
+
+  void visitVarUsage(VarUsage node) {
+    heading('Var', node);
+    output.depth++;
+    output.write('usage ${node.name}');
+    output.writeNodeList('default values', node.defaultValues);
+    output.depth--;
+  }
+
+  void visitExpressions(Expressions node) {
+    heading('Expressions', node);
+    output.depth++;
+    output.writeNodeList('expressions', node.expressions);
+    output.depth--;
+  }
+
+  void visitBinaryExpression(BinaryExpression node) {
+    heading('BinaryExpression', node);
+    // TODO(terry): TBD
+  }
+
+  void visitUnaryExpression(UnaryExpression node) {
+    heading('UnaryExpression', node);
+    // TODO(terry): TBD
+  }
+
+  void visitIdentifier(Identifier node) {
+    heading('Identifier(${output.toValue(node.name)})', node);
+  }
+
+  void visitWildcard(Wildcard node) {
+    heading('Wildcard(*)', node);
+  }
+
+  void visitDartStyleExpression(DartStyleExpression node) {
+    heading('DartStyleExpression', node);
+  }
+
+  void visitFontExpression(FontExpression node) {
+    heading('Dart Style FontExpression', node);
+  }
+
+  void visitBoxExpression(BoxExpression node) {
+    heading('Dart Style BoxExpression', node);
+  }
+
+  void visitMarginExpression(MarginExpression node) {
+    heading('Dart Style MarginExpression', node);
+  }
+
+  void visitBorderExpression(BorderExpression node) {
+    heading('Dart Style BorderExpression', node);
+  }
+
+  void visitHeightExpression(HeightExpression node) {
+    heading('Dart Style HeightExpression', node);
+  }
+
+  void visitPaddingExpression(PaddingExpression node) {
+    heading('Dart Style PaddingExpression', node);
+  }
+
+  void visitWidthExpression(WidthExpression node) {
+    heading('Dart Style WidthExpression', node);
+  }
+}
diff --git a/pkg/csslib/lib/src/validate.dart b/pkg/csslib/lib/src/validate.dart
new file mode 100644
index 0000000..d2301d7
--- /dev/null
+++ b/pkg/csslib/lib/src/validate.dart
@@ -0,0 +1,135 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library csslib.src.validate;
+
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'package:source_maps/span.dart' show Span;
+
+/** Can be thrown on any Css runtime problem includes source location. */
+class CssSelectorException implements Exception {
+  final String _message;
+  final Span _span;
+
+  CssSelectorException(this._message, [this._span]);
+
+  String toString() {
+    var msg = _span == null ? _message : _span.getLocationMessage(_message);
+    return 'CssSelectorException: $msg';
+  }
+}
+
+List<String> classes = [];
+List<String> ids = [];
+
+class Validate {
+  static int _classNameCheck(var selector, int matches) {
+    if (selector.isCombinatorDescendant() ||
+        (selector.isCombinatorNone() && matches == 0)) {
+      if (matches < 0) {
+        String tooMany = selector.simpleSelector.toString();
+        throw new CssSelectorException(
+            'Can not mix Id selector with class selector(s). Id '
+            'selector must be singleton too many starting at $tooMany');
+      }
+
+      return matches + 1;
+    } else {
+      String error = selector.toString();
+      throw new CssSelectorException(
+          'Selectors can not have combinators (>, +, or ~) before $error');
+    }
+  }
+
+  static int _elementIdCheck(var selector, int matches) {
+    if (selector.isCombinatorNone() && matches == 0) {
+      // Perfect just one element id returns matches of -1.
+      return -1;
+    } else if (selector.isCombinatorDescendant()) {
+        String tooMany = selector.simpleSelector.toString();
+        throw new CssSelectorException(
+            'Use of Id selector must be singleton starting at $tooMany');
+    } else {
+      String error = selector.simpleSelector.toString();
+      throw new CssSelectorException(
+          'Selectors can not have combinators (>, +, or ~) before $error');
+    }
+  }
+
+  // Validate the @{css expression} only .class and #elementId are valid inside
+  // of @{...}.
+  static template(List<Selector> selectors) {
+    var errorSelector;                  // signal which selector didn't match.
+    bool found = false;                 // signal if a selector is matched.
+    int matches = 0;                    // < 0 IdSelectors, > 0 ClassSelector
+
+    // At most one selector group (any number of simple selector sequences).
+    assert(selectors.length <= 1);
+
+    for (final sels in selectors) {
+      for (final selector in sels.simpleSelectorSequences) {
+        found = false;
+        var simpleSelector = selector.simpleSelector;
+        if (simpleSelector is ClassSelector) {
+          // Any class name starting with an underscore is a private class name
+          // that doesn't have to match the world of known classes.
+          if (!simpleSelector.name.startsWith('_')) {
+            // TODO(terry): For now iterate through all classes look for faster
+            //              mechanism hash map, etc.
+            for (final className in classes) {
+              if (selector.simpleSelector.name == className) {
+                matches = _classNameCheck(selector, matches);
+                found = true;              // .class found.
+                break;
+              }
+              for (final className2 in classes) {
+                print(className2);
+              }
+            }
+
+          } else {
+            // Don't check any class name that is prefixed with an underscore.
+            // However, signal as found and bump up matches; it's a valid class
+            // name.
+            matches = _classNameCheck(selector, matches);
+            found = true;                 // ._class are always okay.
+          }
+        } else if (simpleSelector is IdSelector) {
+          // Any element id starting with an underscore is a private element id
+          // that doesn't have to match the world of known elemtn ids.
+          if (!simpleSelector.name.startsWith('_')) {
+            for (final id in ids) {
+              if (simpleSelector.name == id) {
+                matches = _elementIdCheck(selector, matches);
+                found = true;             // #id found.
+                break;
+              }
+            }
+          } else {
+            // Don't check any element ID that is prefixed with an underscore.
+            // Signal as found and bump up matches; it's a valid element ID.
+            matches = _elementIdCheck(selector, matches);
+            found = true;                 // #_id are always okay
+          }
+        } else {
+          String badSelector = simpleSelector.toString();
+          throw new CssSelectorException(
+              'Invalid template selector $badSelector');
+        }
+
+        if (!found) {
+          String unknownName = simpleSelector.toString();
+          throw new CssSelectorException('Unknown selector name $unknownName');
+        }
+      }
+    }
+
+    // Every selector must match.
+    Selector selector = selectors[0];
+    assert((matches >= 0 ? matches : -matches) ==
+        selector.simpleSelectorSequences.length);
+  }
+}
+
diff --git a/pkg/csslib/lib/visitor.dart b/pkg/csslib/lib/visitor.dart
new file mode 100644
index 0000000..d2f24c9
--- /dev/null
+++ b/pkg/csslib/lib/visitor.dart
@@ -0,0 +1,445 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library csslib.visitor;
+
+import 'package:source_maps/span.dart' show Span;
+import 'parser.dart';
+
+part 'src/css_printer.dart';
+part 'src/tree.dart';
+part 'src/tree_base.dart';
+part 'src/tree_printer.dart';
+
+abstract class VisitorBase {
+  void visitCssComment(CssComment node);
+  void visitCommentDefinition(CommentDefinition node);
+  void visitStyleSheet(StyleSheet node);
+  void visitTopLevelProduction(TopLevelProduction node);
+  void visitDirective(Directive node);
+  void visitMediaExpression(MediaExpression node);
+  void visitMediaQuery(MediaQuery node);
+  void visitMediaDirective(MediaDirective node);
+  void visitHostDirective(HostDirective node);
+  void visitPageDirective(PageDirective node);
+  void visitCharsetDirective(CharsetDirective node);
+  void visitImportDirective(ImportDirective node);
+  void visitKeyFrameDirective(KeyFrameDirective node);
+  void visitKeyFrameBlock(KeyFrameBlock node);
+  void visitFontFaceDirective(FontFaceDirective node);
+  void visitStyletDirective(StyletDirective node);
+  void visitNamespaceDirective(NamespaceDirective node);
+  void visitVarDefinitionDirective(VarDefinitionDirective node);
+
+  void visitRuleSet(RuleSet node);
+  void visitDeclarationGroup(DeclarationGroup node);
+  void visitMarginGroup(DeclarationGroup node);
+  void visitDeclaration(Declaration node);
+  void visitVarDefinition(VarDefinition node);
+  void visitSelectorGroup(SelectorGroup node);
+  void visitSelector(Selector node);
+  void visitSimpleSelectorSequence(SimpleSelectorSequence node);
+  void visitSimpleSelector(SimpleSelector node);
+  void visitElementSelector(ElementSelector node);
+  void visitNamespaceSelector(NamespaceSelector node);
+  void visitAttributeSelector(AttributeSelector node);
+  void visitIdSelector(IdSelector node);
+  void visitClassSelector(ClassSelector node);
+  void visitPseudoClassSelector(PseudoClassSelector node);
+  void visitPseudoElementSelector(PseudoElementSelector node);
+  void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node);
+  void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node);
+  void visitNegationSelector(NegationSelector node);
+  void visitSelectorExpression(SelectorExpression node);
+
+  void visitUnicodeRangeTerm(UnicodeRangeTerm node);
+  void visitLiteralTerm(LiteralTerm node);
+  void visitHexColorTerm(HexColorTerm node);
+  void visitNumberTerm(NumberTerm node);
+  void visitUnitTerm(UnitTerm node);
+  void visitLengthTerm(LengthTerm node);
+  void visitPercentageTerm(PercentageTerm node);
+  void visitEmTerm(EmTerm node);
+  void visitExTerm(ExTerm node);
+  void visitAngleTerm(AngleTerm node);
+  void visitTimeTerm(TimeTerm node);
+  void visitFreqTerm(FreqTerm node);
+  void visitFractionTerm(FractionTerm node);
+  void visitUriTerm(UriTerm node);
+  void visitResolutionTerm(ResolutionTerm node);
+  void visitChTerm(ChTerm node);
+  void visitRemTerm(RemTerm node);
+  void visitViewportTerm(ViewportTerm node);
+  void visitFunctionTerm(FunctionTerm node);
+  void visitGroupTerm(GroupTerm node);
+  void visitItemTerm(ItemTerm node);
+  void visitIE8Term(IE8Term node);
+  void visitOperatorSlash(OperatorSlash node);
+  void visitOperatorComma(OperatorComma node);
+  void visitOperatorPlus(OperatorPlus node);
+  void visitOperatorMinus(OperatorMinus node);
+  void visitVarUsage(VarUsage node);
+
+  void visitExpressions(Expressions node);
+  void visitBinaryExpression(BinaryExpression node);
+  void visitUnaryExpression(UnaryExpression node);
+
+  void visitIdentifier(Identifier node);
+  void visitWildcard(Wildcard node);
+  void visitThisOperator(ThisOperator node);
+  void visitNegation(Negation node);
+
+  void visitDartStyleExpression(DartStyleExpression node);
+  void visitFontExpression(FontExpression node);
+  void visitBoxExpression(BoxExpression node);
+  void visitMarginExpression(MarginExpression node);
+  void visitBorderExpression(BorderExpression node);
+  void visitHeightExpression(HeightExpression node);
+  void visitPaddingExpression(PaddingExpression node);
+  void visitWidthExpression(WidthExpression node);
+}
+
+/** Base vistor class for the style sheet AST. */
+class Visitor implements VisitorBase {
+  /** Helper function to walk a list of nodes. */
+  void _visitNodeList(list) {
+    // Don't use iterable otherwise the list can't grow while using Visitor.
+    // It certainly can't have items deleted before the index being iterated
+    // but items could be added after the index.
+    for (var index = 0; index < list.length; index++) {
+      list[index].visit(this);
+    }
+  }
+
+  void visitTree(StyleSheet tree) => visitStyleSheet(tree);
+
+  void visitStyleSheet(StyleSheet ss) {
+    _visitNodeList(ss.topLevels);
+  }
+
+  void visitTopLevelProduction(TopLevelProduction node) { }
+
+  void visitDirective(Directive node) { }
+
+  void visitCssComment(CssComment node) { }
+
+  void visitCommentDefinition(CommentDefinition node) { }
+
+  void visitMediaExpression(MediaExpression node) {
+    visitExpressions(node.exprs);
+  }
+
+  void visitMediaQuery(MediaQuery node) {
+    for (var mediaExpr in node.expressions) {
+      visitMediaExpression(mediaExpr);
+    }
+  }
+
+  void visitMediaDirective(MediaDirective node) {
+    for (var mediaQuery in node.mediaQueries) {
+      visitMediaQuery(mediaQuery);
+    }
+    for (var ruleset in node.rulesets) {
+      visitRuleSet(ruleset);
+    }
+  }
+
+  void visitHostDirective(HostDirective node) {
+    for (var ruleset in node.rulesets) {
+      visitRuleSet(ruleset);
+    }
+  }
+
+  void visitPageDirective(PageDirective node) {
+    for (var declGroup in node._declsMargin) {
+      if (declGroup is MarginGroup) {
+        visitMarginGroup(declGroup);
+      } else {
+        visitDeclarationGroup(declGroup);
+      }
+    }
+  }
+
+  void visitCharsetDirective(CharsetDirective node) { }
+
+  void visitImportDirective(ImportDirective node) {
+    for (var mediaQuery in node.mediaQueries) {
+      visitMediaQuery(mediaQuery);
+    }
+  }
+
+  void visitKeyFrameDirective(KeyFrameDirective node) {
+    visitIdentifier(node._name);
+    _visitNodeList(node._blocks);
+  }
+
+  void visitKeyFrameBlock(KeyFrameBlock node) {
+    visitExpressions(node._blockSelectors);
+    visitDeclarationGroup(node._declarations);
+  }
+
+  void visitFontFaceDirective(FontFaceDirective node) {
+    visitDeclarationGroup(node._declarations);
+  }
+
+  void visitStyletDirective(StyletDirective node) {
+    _visitNodeList(node._rulesets);
+  }
+
+  void visitNamespaceDirective(NamespaceDirective node) { }
+
+  void visitVarDefinitionDirective(VarDefinitionDirective node) {
+    visitVarDefinition(node.def);
+  }
+
+  void visitRuleSet(RuleSet node) {
+    visitSelectorGroup(node._selectorGroup);
+    visitDeclarationGroup(node._declarationGroup);
+  }
+
+  void visitDeclarationGroup(DeclarationGroup node) {
+    _visitNodeList(node._declarations);
+  }
+
+  void visitMarginGroup(MarginGroup node) => visitDeclarationGroup(node);
+
+  void visitDeclaration(Declaration node) {
+    visitIdentifier(node._property);
+    if (node._expression != null) node._expression.visit(this);
+  }
+
+  void visitVarDefinition(VarDefinition node) {
+    visitIdentifier(node._property);
+    if (node._expression != null) node._expression.visit(this);
+  }
+
+  void visitSelectorGroup(SelectorGroup node) {
+    _visitNodeList(node.selectors);
+  }
+
+  void visitSelector(Selector node) {
+    _visitNodeList(node._simpleSelectorSequences);
+  }
+
+  void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+    var selector = node._selector;
+    if (selector is NamespaceSelector) {
+      visitNamespaceSelector(selector);
+    } else if (selector is ElementSelector) {
+      visitElementSelector(selector);
+    } else if (selector is IdSelector) {
+      visitIdSelector(selector);
+    } else if (selector is ClassSelector) {
+      visitClassSelector(selector);
+    } else if (selector is PseudoClassFunctionSelector) {
+      visitPseudoClassFunctionSelector(selector);
+    } else if (selector is PseudoElementFunctionSelector) {
+      visitPseudoElementFunctionSelector(selector);
+    } else if (selector is PseudoClassSelector) {
+      visitPseudoClassSelector(selector);
+    } else if (selector is PseudoElementSelector) {
+      visitPseudoElementSelector(selector);
+    } else if (selector is NegationSelector) {
+      visitNegationSelector(selector);
+    } else if (selector is SelectorExpression) {
+      visitSelectorExpression(selector);
+    } else if (selector is AttributeSelector) {
+      visitAttributeSelector(selector);
+    } else {
+      visitSimpleSelector(selector);
+    }
+  }
+
+  void visitSimpleSelector(SimpleSelector node) => node._name.visit(this);
+
+  void visitNamespaceSelector(NamespaceSelector node) {
+    var namespace = node._namespace;
+    if (namespace is Identifier) {
+      visitIdentifier(namespace);
+    } else if (namespace is Wildcard) {
+      visitWildcard(namespace);
+    }
+
+    visitSimpleSelector(node.nameAsSimpleSelector);
+  }
+
+  void visitElementSelector(ElementSelector node) => visitSimpleSelector(node);
+
+  void visitAttributeSelector(AttributeSelector node) {
+    visitSimpleSelector(node);
+  }
+
+  void visitIdSelector(IdSelector node) => visitSimpleSelector(node);
+
+  void visitClassSelector(ClassSelector node) => visitSimpleSelector(node);
+
+  void visitPseudoClassSelector(PseudoClassSelector node) =>
+      visitSimpleSelector(node);
+
+  void visitPseudoElementSelector(PseudoElementSelector node) =>
+      visitSimpleSelector(node);
+
+  void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) =>
+      visitSimpleSelector(node);
+
+  void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) =>
+      visitSimpleSelector(node);
+
+  void visitNegationSelector(NegationSelector node) =>
+      visitSimpleSelector(node);
+
+  void visitSelectorExpression(SelectorExpression node) {
+    _visitNodeList(node._expressions);
+  }
+
+  void visitUnicodeRangeTerm(UnicodeRangeTerm node) { }
+
+  void visitLiteralTerm(LiteralTerm node) { }
+
+  void visitHexColorTerm(HexColorTerm node) { }
+
+  void visitNumberTerm(NumberTerm node) { }
+
+  void visitUnitTerm(UnitTerm node) { }
+
+  void visitLengthTerm(LengthTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitPercentageTerm(PercentageTerm node) {
+    visitLiteralTerm(node);
+  }
+
+  void visitEmTerm(EmTerm node) {
+    visitLiteralTerm(node);
+  }
+
+  void visitExTerm(ExTerm node) {
+    visitLiteralTerm(node);
+  }
+
+  void visitAngleTerm(AngleTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitTimeTerm(TimeTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitFreqTerm(FreqTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitFractionTerm(FractionTerm node) {
+    visitLiteralTerm(node);
+  }
+
+  void visitUriTerm(UriTerm node) {
+    visitLiteralTerm(node);
+  }
+
+  void visitResolutionTerm(ResolutionTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitChTerm(ChTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitRemTerm(RemTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitViewportTerm(ViewportTerm node) {
+    visitUnitTerm(node);
+  }
+
+  void visitFunctionTerm(FunctionTerm node) {
+    visitLiteralTerm(node);
+    visitExpressions(node._params);
+  }
+
+  void visitGroupTerm(GroupTerm node) {
+    for (var term in node._terms) {
+      term.visit(this);
+    }
+  }
+
+  void visitItemTerm(ItemTerm node) {
+    visitNumberTerm(node);
+  }
+
+  void visitIE8Term(IE8Term node) { }
+
+  void visitOperatorSlash(OperatorSlash node) { }
+
+  void visitOperatorComma(OperatorComma node) { }
+
+  void visitOperatorPlus(OperatorPlus node) { }
+
+  void visitOperatorMinus(OperatorMinus node) { }
+
+  void visitVarUsage(VarUsage node) {
+    _visitNodeList(node.defaultValues);
+  }
+
+  void visitExpressions(Expressions node) {
+    _visitNodeList(node.expressions);
+  }
+
+  void visitBinaryExpression(BinaryExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitUnaryExpression(UnaryExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitIdentifier(Identifier node) { }
+
+  void visitWildcard(Wildcard node) { }
+
+  void visitThisOperator(ThisOperator node) { }
+
+  void visitNegation(Negation node) { }
+
+  void visitDartStyleExpression(DartStyleExpression node) { }
+
+  void visitFontExpression(FontExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitBoxExpression(BoxExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitMarginExpression(MarginExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitBorderExpression(BorderExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitHeightExpression(HeightExpression node) {
+    // TODO(terry): TB
+    throw UnimplementedError;
+  }
+
+  void visitPaddingExpression(PaddingExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+
+  void visitWidthExpression(WidthExpression node) {
+    // TODO(terry): TBD
+    throw UnimplementedError;
+  }
+}
diff --git a/pkg/csslib/pubspec.yaml b/pkg/csslib/pubspec.yaml
new file mode 100644
index 0000000..b821941
--- /dev/null
+++ b/pkg/csslib/pubspec.yaml
@@ -0,0 +1,12 @@
+name: csslib
+author: "Web UI Team <web-ui-dev@dartlang.org>"
+description: A library for parsing CSS.
+homepage: https://www.dartlang.org
+dependencies:
+  args: any
+  logging: any
+  path: any
+  source_maps: any
+dev_dependencies:
+  browser: any
+  unittest: any
diff --git a/pkg/csslib/test/compiler_test.dart b/pkg/csslib/test/compiler_test.dart
new file mode 100644
index 0000000..ee37f29
--- /dev/null
+++ b/pkg/csslib/test/compiler_test.dart
@@ -0,0 +1,728 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library compiler_test;
+
+import 'dart:utf';
+import 'package:unittest/unittest.dart';
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'testing.dart';
+
+void testClass() {
+  var errors = [];
+  var input = ".foobar {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var selectorSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+  expect(selectorSeqs.length, 1);
+  final simpSelector = selectorSeqs[0].simpleSelector;
+  expect(simpSelector is ClassSelector, true);
+  expect(selectorSeqs[0].isCombinatorNone, true);
+  expect(simpSelector.name, "foobar");
+}
+
+void testClass2() {
+  var errors = [];
+  var input = ".foobar .bar .no-story {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+  expect(simpleSeqs.length, 3);
+
+  var simpSelector0 = simpleSeqs[0].simpleSelector;
+  expect(simpSelector0 is ClassSelector, true);
+  expect(simpleSeqs[0].isCombinatorNone, true);
+  expect(simpSelector0.name, "foobar");
+
+  var simpSelector1 = simpleSeqs[1].simpleSelector;
+  expect(simpSelector1 is ClassSelector, true);
+  expect(simpleSeqs[1].isCombinatorDescendant, true);
+  expect(simpSelector1.name, "bar");
+
+  var simpSelector2 = simpleSeqs[2].simpleSelector;
+  expect(simpSelector2 is ClassSelector, true);
+  expect(simpleSeqs[2].isCombinatorDescendant, true);
+  expect(simpSelector2.name, "no-story");
+}
+
+void testId() {
+  var errors = [];
+  var input = "#elemId {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 1);
+  var simpSelector = simpleSeqs[0].simpleSelector;
+  expect(simpSelector is IdSelector, true);
+  expect(simpleSeqs[0].isCombinatorNone, true);
+  expect(simpSelector.name, "elemId");
+}
+
+void testElement() {
+  var errors = [];
+  var input = "div {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 1);
+
+  final simpSelector = simpleSeqs[0].simpleSelector;
+  expect(simpSelector is ElementSelector, true);
+  expect(simpleSeqs[0].isCombinatorNone, true);
+  expect(simpSelector.name, "div");
+
+  input = "div div span {}";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 3);
+
+  var simpSelector0 = simpleSeqs[0].simpleSelector;
+  expect(simpSelector0 is ElementSelector, true);
+  expect(simpleSeqs[0].isCombinatorNone, true);
+  expect(simpSelector0.name, "div");
+
+  var simpSelector1 = simpleSeqs[1].simpleSelector;
+  expect(simpSelector1 is ElementSelector, true);
+  expect(simpleSeqs[1].isCombinatorDescendant, true);
+  expect(simpSelector1.name, "div");
+
+  var simpSelector2 = simpleSeqs[2].simpleSelector;
+  expect(simpSelector2 is ElementSelector, true);
+  expect(simpleSeqs[2].isCombinatorDescendant, true);
+  expect(simpSelector2.name, "span");
+}
+
+void testNamespace() {
+  var errors = [];
+  var input = "ns1|div {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 1);
+  var simpSelector = simpleSeqs[0].simpleSelector;
+  expect(simpSelector is NamespaceSelector, true);
+  expect(simpleSeqs[0].isCombinatorNone, true);
+  expect(simpSelector.isNamespaceWildcard, false);
+  expect(simpSelector.namespace, "ns1");
+  var elementSelector = simpSelector.nameAsSimpleSelector;
+  expect(elementSelector is ElementSelector, true);
+  expect(elementSelector.isWildcard, false);
+  expect(elementSelector.name, "div");
+}
+
+void testNamespace2() {
+  var errors = [];
+  var input = "ns1|div div ns2|span .foobar {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 4);
+
+  var simpSelector0 = simpleSeqs[0].simpleSelector;
+  expect(simpSelector0 is NamespaceSelector, true);
+  expect(simpleSeqs[0].isCombinatorNone, true);
+  expect(simpSelector0.namespace, "ns1");
+  var elementSelector0 = simpSelector0.nameAsSimpleSelector;
+  expect(elementSelector0 is ElementSelector, true);
+  expect(elementSelector0.isWildcard, false);
+  expect(elementSelector0.name, "div");
+
+  var simpSelector1 = simpleSeqs[1].simpleSelector;
+  expect(simpSelector1 is ElementSelector, true);
+  expect(simpleSeqs[1].isCombinatorDescendant, true);
+  expect(simpSelector1.name, "div");
+
+  var simpSelector2 = simpleSeqs[2].simpleSelector;
+  expect(simpSelector2 is NamespaceSelector, true);
+  expect(simpleSeqs[2].isCombinatorDescendant, true);
+  expect(simpSelector2.namespace, "ns2");
+  var elementSelector2 = simpSelector2.nameAsSimpleSelector;
+  expect(elementSelector2 is ElementSelector, true);
+  expect(elementSelector2.isWildcard, false);
+  expect(elementSelector2.name, "span");
+
+  var simpSelector3 = simpleSeqs[3].simpleSelector;
+  expect(simpSelector3 is ClassSelector, true);
+  expect(simpleSeqs[3].isCombinatorDescendant, true);
+  expect(simpSelector3.name, "foobar");
+}
+
+void testSelectorGroups() {
+  var errors = [];
+  var input =
+      "div, .foobar ,#elemId, .xyzzy .test, ns1|div div #elemId .foobar {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 5);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var groupSelector0 = ruleset.selectorGroup.selectors[0];
+  expect(groupSelector0.simpleSelectorSequences.length, 1);
+  var selector0 = groupSelector0.simpleSelectorSequences[0];
+  var simpleSelector0 = selector0.simpleSelector;
+  expect(simpleSelector0 is ElementSelector, true);
+  expect(selector0.isCombinatorNone, true);
+  expect(simpleSelector0.name, "div");
+
+  var groupSelector1 = ruleset.selectorGroup.selectors[1];
+  expect(groupSelector1.simpleSelectorSequences.length, 1);
+  var selector1 = groupSelector1.simpleSelectorSequences[0];
+  var simpleSelector1 = selector1.simpleSelector;
+  expect(simpleSelector1 is ClassSelector, true);
+  expect(selector1.isCombinatorNone, true);
+  expect(simpleSelector1.name, "foobar");
+
+  var groupSelector2 = ruleset.selectorGroup.selectors[2];
+  expect(groupSelector2.simpleSelectorSequences.length, 1);
+  var selector2 = groupSelector2.simpleSelectorSequences[0];
+  var simpleSelector2 = selector2.simpleSelector;
+  expect(simpleSelector2 is IdSelector, true);
+  expect(selector2.isCombinatorNone, true);
+  expect(simpleSelector2.name, "elemId");
+
+  var groupSelector3 = ruleset.selectorGroup.selectors[3];
+  expect(groupSelector3.simpleSelectorSequences.length, 2);
+
+  var selector30 = groupSelector3.simpleSelectorSequences[0];
+  var simpleSelector30 = selector30.simpleSelector;
+  expect(simpleSelector30 is ClassSelector, true);
+  expect(selector30.isCombinatorNone, true);
+  expect(simpleSelector30.name, "xyzzy");
+
+  var selector31 = groupSelector3.simpleSelectorSequences[1];
+  var simpleSelector31 = selector31.simpleSelector;
+  expect(simpleSelector31 is ClassSelector, true);
+  expect(selector31.isCombinatorDescendant, true);
+  expect(simpleSelector31.name, "test");
+
+  var groupSelector4 = ruleset.selectorGroup.selectors[4];
+  expect(groupSelector4.simpleSelectorSequences.length, 4);
+
+  var selector40 = groupSelector4.simpleSelectorSequences[0];
+  var simpleSelector40 = selector40.simpleSelector;
+  expect(simpleSelector40 is NamespaceSelector, true);
+  expect(selector40.isCombinatorNone, true);
+  expect(simpleSelector40.namespace, "ns1");
+  var elementSelector = simpleSelector40.nameAsSimpleSelector;
+  expect(elementSelector is ElementSelector, true);
+  expect(elementSelector.isWildcard, false);
+  expect(elementSelector.name, "div");
+
+  var selector41 = groupSelector4.simpleSelectorSequences[1];
+  var simpleSelector41 = selector41.simpleSelector;
+  expect(simpleSelector41 is ElementSelector, true);
+  expect(selector41.isCombinatorDescendant, true);
+  expect(simpleSelector41.name, "div");
+
+  var selector42 = groupSelector4.simpleSelectorSequences[2];
+  var simpleSelector42 = selector42.simpleSelector;
+  expect(simpleSelector42 is IdSelector, true);
+  expect(selector42.isCombinatorDescendant, true);
+  expect(simpleSelector42.name, "elemId");
+
+  var selector43 = groupSelector4.simpleSelectorSequences[3];
+  var simpleSelector43 = selector43.simpleSelector;
+  expect(selector43.isCombinatorDescendant, true);
+  expect(simpleSelector43.name, "foobar");
+}
+
+void testCombinator() {
+  var errors = [];
+  var input = ".foobar > .bar + .no-story ~ myNs|div #elemId {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 5);
+
+  var selector0 = simpleSeqs[0];
+  var simpleSelector0 = selector0.simpleSelector;
+  expect(simpleSelector0 is ClassSelector, true);
+  expect(selector0.isCombinatorNone, true);
+  expect(simpleSelector0.name, "foobar");
+
+  var selector1 = simpleSeqs[1];
+  var simpleSelector1 = selector1.simpleSelector;
+  expect(simpleSelector1 is ClassSelector, true);
+  expect(selector1.isCombinatorGreater, true);
+  expect(simpleSelector1.name, "bar");
+
+  var selector2 = simpleSeqs[2];
+  var simpleSelector2 = selector2.simpleSelector;
+  expect(simpleSelector2 is ClassSelector, true);
+  expect(selector2.isCombinatorPlus, true);
+  expect(simpleSelector2.name, "no-story");
+
+  var selector3 = simpleSeqs[3];
+  var simpleSelector3 = selector3.simpleSelector;
+  expect(simpleSelector3 is NamespaceSelector, true);
+  expect(selector3.isCombinatorTilde, true);
+  expect(simpleSelector3.namespace, "myNs");
+  var elementSelector = simpleSelector3.nameAsSimpleSelector;
+  expect(elementSelector is ElementSelector, true);
+  expect(elementSelector.isWildcard, false);
+  expect(elementSelector.name, "div");
+
+  var selector4 = simpleSeqs[4];
+  var simpleSelector4 = selector4.simpleSelector;
+  expect(simpleSelector4 is IdSelector, true);
+  expect(selector4.isCombinatorDescendant, true);
+  expect(simpleSelector4.name, "elemId");
+}
+
+void testWildcard() {
+  var errors = [];
+  var input = "* {}";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  var ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  var simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 1);
+  var simpSelector = simpleSeqs[0].simpleSelector;
+  expect(simpSelector is ElementSelector, true);
+  expect(simpleSeqs[0].isCombinatorNone, true);
+  expect(simpSelector.isWildcard, true);
+  expect(simpSelector.name, "*");
+
+  input = "*.foobar {}";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 2);
+
+  var selector0 = simpleSeqs[0];
+  var simpleSelector0 = selector0.simpleSelector;
+  expect(simpleSelector0 is ElementSelector, true);
+  expect(selector0.isCombinatorNone, true);
+  expect(simpleSelector0.isWildcard, true);
+  expect(simpleSelector0.name, "*");
+
+  var selector1 = simpleSeqs[1];
+  var simpleSelector1 = selector1.simpleSelector;
+  expect(simpleSelector1 is ClassSelector, true);
+  expect(selector1.isCombinatorNone, true);
+  expect(simpleSelector1.name, "foobar");
+
+  input = "myNs|*.foobar {}";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels.length, 1);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 2);
+
+  selector0 = simpleSeqs[0];
+  simpleSelector0 = selector0.simpleSelector;
+  expect(simpleSelector0 is NamespaceSelector, true);
+  expect(selector0.isCombinatorNone, true);
+  expect(simpleSelector0.isNamespaceWildcard, false);
+  var elementSelector = simpleSelector0.nameAsSimpleSelector;
+  expect("myNs", simpleSelector0.namespace);
+  expect(elementSelector.isWildcard, true);
+  expect("*", elementSelector.name);
+
+  selector1 = simpleSeqs[1];
+  simpleSelector1 = selector1.simpleSelector;
+  expect(simpleSelector1 is ClassSelector, true);
+  expect(selector1.isCombinatorNone, true);
+  expect("foobar", simpleSelector1.name);
+
+  input = "*|*.foobar {}";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(stylesheet.topLevels[0] is RuleSet, true);
+  ruleset = stylesheet.topLevels[0];
+  expect(ruleset.selectorGroup.selectors.length, 1);
+  expect(ruleset.declarationGroup.declarations.length, 0);
+
+  simpleSeqs = ruleset.selectorGroup.selectors[0].simpleSelectorSequences;
+
+  expect(simpleSeqs.length, 2);
+
+  selector0 = simpleSeqs[0];
+  simpleSelector0 = selector0.simpleSelector;
+  expect(simpleSelector0 is NamespaceSelector, true);
+  expect(selector0.isCombinatorNone, true);
+  expect(simpleSelector0.isNamespaceWildcard, true);
+  expect("*", simpleSelector0.namespace);
+  elementSelector = simpleSelector0.nameAsSimpleSelector;
+  expect(elementSelector.isWildcard, true);
+  expect("*", elementSelector.name);
+
+  selector1 = simpleSeqs[1];
+  simpleSelector1 = selector1.simpleSelector;
+  expect(simpleSelector1 is ClassSelector, true);
+  expect(selector1.isCombinatorNone, true);
+  expect("foobar", simpleSelector1.name);
+}
+
+/** Test List<int> as input to parser. */
+void testArrayOfChars() {
+  var errors = [];
+  var input = '<![CDATA[.foo { '
+      'color: red; left: 20px; top: 20px; width: 100px; height:200px'
+    '}'
+    '#div {'
+      'color : #00F578; border-color: #878787;'
+    '}]]>';
+
+  var stylesheet = parse(encodeUtf8(input), errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  expect(prettyPrint(stylesheet), r'''
+.foo {
+  color: #f00;
+  left: 20px;
+  top: 20px;
+  width: 100px;
+  height: 200px;
+}
+#div {
+  color: #00F578;
+  border-color: #878787;
+}''');
+}
+
+void testPseudo() {
+  var errors = [];
+
+  final input = r'''
+html:lang(fr-ca) { quotes: '" ' ' "' }
+zoom: { }
+
+a:link { color: red }
+:link  { color: blue }
+
+a:focus { background: yellow }
+a:focus:hover { background: white }
+
+p.special:first-letter {color: #ffd800}
+
+p:not(#example){
+  background-color: yellow;
+}
+
+input:not([DISABLED]){
+  background-color: yellow;
+}
+
+html|*:not(:link):not(:visited) {
+  border: 1px solid black;
+}
+
+*:not(FOO) {
+  height: 20px;
+}
+
+*|*:not(*) {
+  color: orange;
+}
+
+*|*:not(:hover) {
+  color: magenta;
+}
+
+p:nth-child(3n-3) { }
+
+div:nth-child(2n) { color : red; }
+''';
+
+  var stylesheet = parseCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), r'''
+html:lang(fr-ca) {
+  quotes: "\" " " \"";
+}
+zoom {
+}
+a:link {
+  color: #f00;
+}
+:link {
+  color: #00f;
+}
+a:focus {
+  background: #ff0;
+}
+a:focus:hover {
+  background: #fff;
+}
+p.special:first-letter {
+  color: #ffd800;
+}
+p:not(#example) {
+  background-color: #ff0;
+}
+input:not([DISABLED]) {
+  background-color: #ff0;
+}
+html|*:not(:link):not(:visited) {
+  border: 1px solid #000;
+}
+*:not(FOO) {
+  height: 20px;
+}
+*|*:not(*) {
+  color: #ffa500;
+}
+*|*:not(:hover) {
+  color: #f0f;
+}
+p:nth-child(3n-3) {
+}
+div:nth-child(2n) {
+  color: #f00;
+}''');
+}
+
+void testAttribute() {
+  // TODO(terry): Implement
+}
+
+void testNegation() {
+  // TODO(terry): Implement
+}
+
+void testHost() {
+  var errors = [];
+  var input = '@host { '
+      ':scope {'
+        'white-space: nowrap;'
+        'overflow-style: marquee-line;'
+        'overflow-x: marquee;'
+      '}'
+      '* { color: red; }'
+      '*:hover { font-weight: bold; }'
+      ':nth-child(odd) { color: blue; }'
+    '}';
+  var stylesheet = parseCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), r'''
+@host {
+:scope {
+  white-space: nowrap;
+  overflow-style: marquee-line;
+  overflow-x: marquee;
+}
+* {
+  color: #f00;
+}
+*:hover {
+  font-weight: bold;
+}
+:nth-child(odd) {
+  color: #00f;
+}
+}''');
+}
+
+// TODO(terry): Move to emitter_test.dart when real emitter exist.
+void testEmitter() {
+  var errors = [];
+  var input = '.foo { '
+      'color: red; left: 20px; top: 20px; width: 100px; height:200px'
+    '}'
+    '#div {'
+      'color : #00F578; border-color: #878787;'
+    '}';
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  walkTree(stylesheet);
+
+  expect(prettyPrint(stylesheet), r'''
+.foo {
+  color: #f00;
+  left: 20px;
+  top: 20px;
+  width: 100px;
+  height: 200px;
+}
+#div {
+  color: #00F578;
+  border-color: #878787;
+}''');
+}
+
+main() {
+  test('Classes', testClass);
+  test('Classes 2', testClass2);
+  test('Ids', testId);
+  test('Elements', testElement);
+  test('Namespace', testNamespace);
+  test('Namespace 2', testNamespace2);
+  test('Selector Groups', testSelectorGroups);
+  test('Combinator', testCombinator);
+  test('Wildcards', testWildcard);
+  test('Pseudo', testPseudo);
+  test('Attributes', testAttribute);
+  test('Negation', testNegation);
+  test('@host', testHost);
+  test('Parse List<int> as input', testArrayOfChars);
+  test('Simple Emitter', testEmitter);
+}
diff --git a/pkg/csslib/test/declaration_test.dart b/pkg/csslib/test/declaration_test.dart
new file mode 100644
index 0000000..3d6912c
--- /dev/null
+++ b/pkg/csslib/test/declaration_test.dart
@@ -0,0 +1,1036 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library declaration_test;
+
+import 'package:unittest/unittest.dart';
+import 'testing.dart';
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+
+
+/** CSS compiler options no checks in in memory style sheet. */
+List options = ['--no-colors', 'memory'];
+
+void testSimpleTerms() {
+  var errors = [];
+  final String input = r'''
+@ import url("test.css");
+.foo {
+  background-color: #191919;
+  width: 10PX;
+  height: 22mM !important;
+  border-width: 20cm;
+  margin-width: 33%;
+  border-height: 30EM;
+  width: .6in;
+  length: 1.2in;
+  -web-stuff: -10Px;
+}''';
+  final String generated = r'''
+@import "test.css";
+.foo {
+  background-color: #191919;
+  width: 10px;
+  height: 22mm !important;
+  border-width: 20cm;
+  margin-width: 33%;
+  border-height: 30em;
+  width: .6in;
+  length: 1.2in;
+  -web-stuff: -10px;
+}''';
+
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  final String input2 = r'''
+* {
+  border-color: green;
+}''';
+  final String generated2 = r'''
+* {
+  border-color: #008000;
+}''';
+
+  stylesheet = parseCss(input2, errors: errors..clear());
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated2);
+}
+
+/**
+ * Declarations with comments, references with single-quotes, double-quotes,
+ * no quotes.  Hex values with # and letters, and functions (rgba, url, etc.)
+ */
+void testDeclarations() {
+  var errors = [];
+  final String input = r'''
+.more {
+  color: white;
+  color: black;
+  color: cyan;
+  color: red;
+  color: #aabbcc;  /* test -- 3 */
+  color: blue;
+  background-image: url(http://test.jpeg);
+  background-image: url("http://double_quote.html");
+  background-image: url('http://single_quote.html');
+  color: rgba(10,20,255);  <!-- test CDO/CDC  -->
+  color: #123aef;   /* hex # part integer and part identifier */
+}''';
+  final String generated = r'''
+.more {
+  color: #fff;
+  color: #000;
+  color: #0ff;
+  color: #f00;
+  color: #abc;
+  color: #00f;
+  background-image: url("http://test.jpeg");
+  background-image: url("http://double_quote.html");
+  background-image: url("http://single_quote.html");
+  color: rgba(10, 20, 255);
+  color: #123aef;
+}''';
+
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testIdentifiers() {
+  var errors = [];
+  final String input = r'''
+#da {
+  height: 100px;
+}
+#foo {
+  width: 10px;
+  color: #ff00cc;
+}
+''';
+  final String generated = r'''
+#da {
+  height: 100px;
+}
+#foo {
+  width: 10px;
+  color: #f0c;
+}''';
+
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testComposites() {
+  var errors = [];
+  final String input = r'''
+.xyzzy {
+  border: 10px 80px 90px 100px;
+  width: 99%;
+}
+@-webkit-keyframes pulsate {
+  0% {
+    -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+  }
+}''';
+  final String generated = r'''
+.xyzzy {
+  border: 10px 80px 90px 100px;
+  width: 99%;
+}
+@-webkit-keyframes pulsate {
+  0% {
+  -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+  }
+}''';
+
+  var stylesheet = parseCss(input, errors: errors);
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testUnits() {
+  var errors = [];
+  final String input = r'''
+#id-1 {
+  transition: color 0.4s;
+  animation-duration: 500ms;
+  top: 1em;
+  left: 200ex;
+  right: 300px;
+  bottom: 400cm;
+  border-width: 2.5mm;
+  margin-top: .5in;
+  margin-left: 5pc;
+  margin-right: 5ex;
+  margin-bottom: 5ch;
+  font-size: 10pt;
+  padding-top: 22rem;
+  padding-left: 33vw;
+  padding-right: 34vh;
+  padding-bottom: 3vmin;
+  transform: rotate(20deg);
+  voice-pitch: 10hz;
+}
+#id-2 {
+  left: 2fr;
+  font-size: 10vmax;
+  transform: rotatex(20rad);
+  voice-pitch: 10khz;
+  -web-kit-resolution: 2dpi;    /* Bogus property name testing dpi unit. */
+}
+#id-3 {
+  -web-kit-resolution: 3dpcm;   /* Bogus property name testing dpi unit. */
+  transform: rotatey(20grad);
+}
+#id-4 {
+  -web-kit-resolution: 4dppx;   /* Bogus property name testing dpi unit. */
+  transform: rotatez(20turn);
+}
+''';
+
+  final String generated = r'''
+#id-1 {
+  transition: color 0.4s;
+  animation-duration: 500ms;
+  top: 1em;
+  left: 200ex;
+  right: 300px;
+  bottom: 400cm;
+  border-width: 2.5mm;
+  margin-top: .5in;
+  margin-left: 5pc;
+  margin-right: 5ex;
+  margin-bottom: 5ch;
+  font-size: 10pt;
+  padding-top: 22rem;
+  padding-left: 33vw;
+  padding-right: 34vh;
+  padding-bottom: 3vmin;
+  transform: rotate(20deg);
+  voice-pitch: 10hz;
+}
+#id-2 {
+  left: 2fr;
+  font-size: 10vmax;
+  transform: rotatex(20rad);
+  voice-pitch: 10khz;
+  -web-kit-resolution: 2dpi;
+}
+#id-3 {
+  -web-kit-resolution: 3dpcm;
+  transform: rotatey(20grad);
+}
+#id-4 {
+  -web-kit-resolution: 4dppx;
+  transform: rotatez(20turn);
+}''';
+
+  var stylesheet = parseCss(input, errors: errors, opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testUnicode() {
+  var errors = [];
+  final String input = r'''
+.toggle:after {
+  content: '✔';
+  line-height: 43px;
+  font-size: 20px;
+  color: #d9d9d9;
+  text-shadow: 0 -1px 0 #bfbfbf;
+}
+''';
+
+  final String generated = r'''
+.toggle:after {
+  content: "✔";
+  line-height: 43px;
+  font-size: 20px;
+  color: #d9d9d9;
+  text-shadow: 0 -1px 0 #bfbfbf;
+}''';
+
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testNewerCss() {
+  var errors = [];
+  final String input = r'''
+@media screen,print {
+  .foobar_screen {
+    width: 10px;
+  }
+}
+@page {
+  height: 22px;
+  size: 3in 3in;
+}
+@page : left {
+  width: 10px;
+}
+@page bar : left { @top-left { margin: 8px; } }
+@charset "ISO-8859-1";
+@charset 'ASCII';''';
+
+  final String generated = r'''
+@media screen, print {
+.foobar_screen {
+  width: 10px;
+}
+}
+@page {
+  height: 22px;
+  size: 3in 3in;
+}
+@page:left {
+  width: 10px;
+}
+@page bar:left {
+@top-left {
+  margin: 8px;
+}
+}
+@charset "ISO-8859-1";
+@charset "ASCII";''';
+
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testMediaQueries() {
+  var errors = [];
+  String input = '''
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+  .todo-item .toggle {
+    background: none;
+  }
+  #todo-item .toggle {
+    height: 40px;
+  }
+}''';
+  String generated = '''
+@media screen AND (-webkit-min-device-pixel-ratio:0) {
+.todo-item .toggle {
+  background: none;
+}
+#todo-item .toggle {
+  height: 40px;
+}
+}''';
+
+  var stylesheet = parseCss(input, errors: errors, opts: options);
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  input = '''
+  @media handheld and (min-width: 20em), 
+         screen and (min-width: 20em) {
+    #id { color: red; }
+    .myclass { height: 20px; }
+  }
+  @media print and (min-resolution: 300dpi) {
+    #anotherId {
+      color: #fff;
+    }
+  }
+  @media print and (min-resolution: 280dpcm) {
+    #finalId {
+      color: #aaa;
+    }
+    .class2 {
+      border: 20px;
+    }
+  }''';
+  generated =
+    '''@media handheld AND (min-width:20em), screen AND (min-width:20em) {
+#id {
+  color: #f00;
+}
+.myclass {
+  height: 20px;
+}
+} @media print AND (min-resolution:300dpi) {
+#anotherId {
+  color: #fff;
+}
+} @media print AND (min-resolution:280dpcm) {
+#finalId {
+  color: #aaa;
+}
+.class2 {
+  border: 20px;
+}
+}''';
+
+  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  input = '''
+@media only screen and (min-device-width: 4000px) and
+    (min-device-height: 2000px), screen (another: 100px) {
+      html {
+        font-size: 10em;
+      }
+    }''';
+  generated = '@media ONLY screen AND (min-device-width:4000px) '
+      'AND (min-device-height:2000px), screen (another:100px) {\n'
+      'html {\n  font-size: 10em;\n}\n}';
+
+  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  input = '''
+@media screen,print (min-device-width: 4000px) and
+    (min-device-height: 2000px), screen (another: 100px) {
+      html {
+        font-size: 10em;
+      }
+    }''';
+  generated = '@media screen, print (min-device-width:4000px) AND '
+      '(min-device-height:2000px), screen (another:100px) {\n'
+      'html {\n  font-size: 10em;\n}\n}';
+
+  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  input = '''
+@import "test.css" ONLY screen, NOT print (min-device-width: 4000px);''';
+  generated =
+      '@import "test.css" ONLY screen, NOT print (min-device-width:4000px);';
+
+  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testFontFace() {
+  var errors = [];
+
+  final String input = '''
+@font-face {
+  font-family: BBCBengali;
+  src: url(fonts/BBCBengali.ttf) format("opentype");
+  unicode-range: U+0A-FF, U+980-9FF, U+????, U+3???;
+}''';
+  final String generated = '''@font-face  {
+  font-family: BBCBengali;
+  src: url("fonts/BBCBengali.ttf") format("opentype");
+  unicode-range: U+0A-FF, U+980-9FF, U+????, U+3???;
+}''';
+  var stylesheet = parseCss(input, errors: errors, opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  final String input1 = '''
+@font-face {
+  font-family: Gentium;
+  src: url(http://example.com/fonts/Gentium.ttf);
+  src: url(http://example.com/fonts/Gentium.ttf);
+}''';
+  final String generated1 = '''@font-face  {
+  font-family: Gentium;
+  src: url("http://example.com/fonts/Gentium.ttf");
+  src: url("http://example.com/fonts/Gentium.ttf");
+}''';
+
+  stylesheet = parseCss(input1, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated1);
+
+  final String input2 = '''
+@font-face {
+src: url(ideal-sans-serif.woff) format("woff"),
+     url(basic-sans-serif.ttf) format("opentype"),
+     local(Gentium Bold);
+}''';
+  final String generated2 =
+      '@font-face  {\n'
+      '  src: url("ideal-sans-serif.woff") '
+      'format("woff"), url("basic-sans-serif.ttf") '
+      'format("opentype"), local(Gentium Bold);\n}';
+
+  stylesheet = parseCss(input2, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated2);
+
+  final String input3 = '''@font-face {
+  font-family: MyGentium Text Ornaments;
+  src: local(Gentium Bold),   /* full font name */
+       local(Gentium-Bold),   /* Postscript name */
+       url(GentiumBold.ttf);  /* otherwise, download it */
+  font-weight: bold;
+}''';
+  final String generated3 = '''@font-face  {
+  font-family: MyGentium Text Ornaments;
+  src: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+  font-weight: bold;
+}''';
+
+  stylesheet = parseCss(input3, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated3);
+
+  final String input4 = '''
+@font-face {
+  font-family: STIXGeneral;
+  src: local(STIXGeneral), url(/stixfonts/STIXGeneral.otf);
+  unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+}''';
+  final String generated4 = '''@font-face  {
+  font-family: STIXGeneral;
+  src: local(STIXGeneral), url("/stixfonts/STIXGeneral.otf");
+  unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+}''';
+  stylesheet = parseCss(input4, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated4);
+}
+
+void testCssFile() {
+  var errors = [];
+  final String input = r'''
+@import 'simple.css'
+@import "test.css" print
+@import url(test.css) screen, print
+@import url(http://google.com/maps/maps.css);
+
+div[href^='test'] {
+  height: 10px;
+}
+
+@-webkit-keyframes pulsate {
+  from {
+    -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+  }
+  10% {
+    -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+  }
+  30% {
+    -webkit-transform: translate3d(0, 2, 0) scale(1.0);
+  }
+}
+
+.foobar {
+    grid-columns: 10px ("content" 1fr 10px)[4];
+}
+
+.test-background {
+  background:  url(http://www.foo.com/bar.png);
+}
+''';
+
+  final String generated =
+      '@import "simple.css"; '
+      '@import "test.css" print; '
+      '@import "test.css" screen, print; '
+      '@import "http://google.com/maps/maps.css";\n'
+      'div[href^="test"] {\n'
+      '  height: 10px;\n'
+      '}\n'
+      '@-webkit-keyframes pulsate {\n'
+      '  from {\n'
+      '  -webkit-transform: translate3d(0, 0, 0) scale(1.0);\n'
+      '  }\n'
+      '  10% {\n'
+      '  -webkit-transform: translate3d(0, 0, 0) scale(1.0);\n'
+      '  }\n'
+      '  30% {\n'
+      '  -webkit-transform: translate3d(0, 2, 0) scale(1.0);\n'
+      '  }\n'
+      '}\n'
+      '.foobar {\n'
+      '  grid-columns: 10px ("content" 1fr 10px) [4];\n'
+      '}\n'
+      '.test-background {\n'
+      '  background: url("http://www.foo.com/bar.png");\n'
+      '}';
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testCompactEmitter() {
+  var errors = [];
+
+  // Check !import compactly emitted.
+  final String input = r'''
+div {
+  color: green !important;
+}
+''';
+  final String generated = "div { color: green!important; }";
+
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(compactOuptut(stylesheet), generated);
+
+  // Check namespace directive compactly emitted.
+  final String input2 = "@namespace a url(http://www.example.org/a);";
+  final String generated2 = "@namespace a url(http://www.example.org/a);";
+
+  var stylesheet2 = parseCss(input2, errors: errors..clear());
+
+  expect(stylesheet2 != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(compactOuptut(stylesheet2), generated2);
+}
+
+void testNotSelectors() {
+  var errors = [];
+
+  final String input = r'''
+.details:not(.open-details) x-element,
+.details:not(.open-details) .summary {
+  overflow: hidden;
+}
+
+.details:not(.open-details) x-icon {
+  margin-left: 99px;
+}
+
+.kind-class .details:not(.open-details) x-icon {
+  margin-left: 0px;
+}
+
+.name {
+  margin-left: 0px;
+}
+
+.details:not(.open-details) .the-class {
+  width: 80px;
+}
+
+*:focus
+{
+  outline: none;
+}
+
+body > h2:not(:first-of-type):not(:last-of-type) {
+  color: red;
+}
+
+.details-1:not([DISABLED]) {
+  outline: none;
+}
+
+html|*:not(:link):not(:visited) {
+  width: 92%;
+}
+
+*|*:not(*) {
+  font-weight: bold;
+}
+
+*:not(:not([disabled])) { color: blue; }
+''';
+  final String generated = r'''
+.details:not(.open-details) x-element, .details:not(.open-details) .summary {
+  overflow: hidden;
+}
+.details:not(.open-details) x-icon {
+  margin-left: 99px;
+}
+.kind-class .details:not(.open-details) x-icon {
+  margin-left: 0px;
+}
+.name {
+  margin-left: 0px;
+}
+.details:not(.open-details) .the-class {
+  width: 80px;
+}
+*:focus {
+  outline: none;
+}
+body > h2:not(:first-of-type):not(:last-of-type) {
+  color: #f00;
+}
+.details-1:not([DISABLED]) {
+  outline: none;
+}
+html|*:not(:link):not(:visited) {
+  width: 92%;
+}
+*|*:not(*) {
+  font-weight: bold;
+}
+*:not(:not([disabled])) {
+  color: #00f;
+}''';
+
+  var stylesheet = parseCss(input, errors: errors, opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testIE() {
+  var errors = [];
+  final String input =
+".test {\n"
+"  filter: progid:DXImageTransform.Microsoft.gradient"
+"(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');\n"
+"}";
+  final String generated =
+".test {\n"
+"  filter: progid:DXImageTransform.Microsoft.gradient"
+"(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');\n"
+"}";
+
+  var stylesheet = parseCss(input,  errors: errors, opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  final String input2 =
+".test {\n"
+"  filter: progid:DXImageTransform.Microsoft.gradient"
+"(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670')\n"
+"        progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n"
+"}";
+
+  final String generated2 =
+".test {\n"
+"  filter: progid:DXImageTransform.Microsoft.gradient"
+"(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670')\n"
+"         progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n"
+"}";
+
+  stylesheet = parseCss(input2, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated2);
+
+  final String input3 = '''
+div {
+  filter: alpha(opacity=80);          /* IE7 and under */
+  -ms-filter: "Alpha(Opacity=40)";    /* IE8 and newer */
+
+  Filter: Blur(Add = 0, Direction = 225, Strength = 10);
+  Filter: FlipV;
+  Filter: Gray;
+  FILTER: Chroma(Color = #000000) Mask(Color=#00FF00);
+  Filter: Alpha(Opacity=100, FinishOpacity=0, Style=2, StartX=20, StartY=40, 
+      FinishX=0, FinishY=0) Wave(Add=0, Freq=5, LightStrength=20, 
+      Phase=220, Strength=10);
+}
+''';
+  final String generated3 = 'div {\n  filter: alpha(opacity=80);\n'
+      '  -ms-filter: "Alpha(Opacity=40)";\n'
+      '  Filter: Blur(Add = 0, Direction = 225, Strength = 10);\n'
+      '  Filter: FlipV;\n  Filter: Gray;\n'
+      '  FILTER: Chroma(Color = #000000)  Mask(Color=#00FF00);\n'
+      '  Filter: Alpha(Opacity=100, FinishOpacity=0, Style=2, '
+      'StartX=20, StartY=40, \n'
+      '      FinishX=0, FinishY=0)  Wave(Add=0, Freq=5, LightStrength=20, \n'
+      '      Phase=220, Strength=10);\n}';
+
+  stylesheet = parseCss(input3, errors: errors..clear(), opts: options);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated3);
+}
+
+/**
+ *  Test IE specific declaration syntax:
+ *    IE6 property name prefixed with _ (normal CSS property name can start
+ *    with an underscore).
+ *
+ *    IE7 or below property add asterisk before the CSS property.
+ *
+ *    IE8 or below add \9 at end of declaration expression e.g.,
+ *        background: red\9;
+ */
+void testIEDeclaration() {
+  var errors = [];
+
+  final input = '''
+.testIE-6 {
+  _zoom : 5;
+}
+.clearfix {
+  *zoom: 1;
+}
+audio, video {
+  display: inline-block;
+  *display: inline;
+  *zoom: 1;
+}
+input {
+  *overflow: visible;
+  line-height: normal;
+}
+.uneditable-input:focus {
+  border-color: rgba(82, 168, 236, 0.8);
+  outline: 0;
+  outline: thin dotted \\9; /* IE6-9 */
+}
+
+input[type="radio"], input[type="checkbox"] {
+  margin-top: 1px \\9;
+  *margin-top: 0;
+}
+
+input.search-query {
+  padding-right: 14px;
+  padding-right: 4px \\9;
+  padding-left: 14px;
+  padding-left: 4px \\9; /* IE7-8 no border-radius, don't indent padding. */
+}
+
+.btn.active {
+  background-color: #cccccc \\9;
+}
+
+@-webkit-keyframes progress-bar-stripes {
+from {
+background-position: 40px 0;
+}
+to {
+background-position: 0 0;
+}
+}
+
+@-moz-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-ms-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-o-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}''';
+
+  final generated = '''.testIE-6 {
+  _zoom: 5;
+}
+.clearfix {
+  *zoom: 1;
+}
+audio, video {
+  display: inline-block;
+  *display: inline;
+  *zoom: 1;
+}
+input {
+  *overflow: visible;
+  line-height: normal;
+}
+.uneditable-input:focus {
+  border-color: rgba(82, 168, 236, 0.8);
+  outline: 0;
+  outline: thin dotted \\9;
+}
+input[type="radio"], input[type="checkbox"] {
+  margin-top: 1px \\9;
+  *margin-top: 0;
+}
+input.search-query {
+  padding-right: 14px;
+  padding-right: 4px \\9;
+  padding-left: 14px;
+  padding-left: 4px \\9;
+}
+.btn.active {
+  background-color: #ccc \\9;
+}
+@-webkit-keyframes progress-bar-stripes {
+  from {
+  background-position: 40px 0;
+  }
+  to {
+  background-position: 0 0;
+  }
+}
+@-moz-keyframes progress-bar-stripes {
+  from {
+  background-position: 40px 0;
+  }
+  to {
+  background-position: 0 0;
+  }
+}
+@keyframes progress-bar-stripes {
+  from {
+  background-position: 40px 0;
+  }
+  to {
+  background-position: 0 0;
+  }
+}
+@-o-keyframes progress-bar-stripes {
+  from {
+  background-position: 40px 0;
+  }
+  to {
+  background-position: 0 0;
+  }
+}
+@keyframes progress-bar-stripes {
+  from {
+  background-position: 40px 0;
+  }
+  to {
+  background-position: 0 0;
+  }
+}''';
+
+  var stylesheet = parseCss(input, errors: errors, opts: options);
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void testHangs() {
+  final optionErrors = ['--no-colors', '--warnings_as_errors', 'memory'];
+  var errors = [];
+
+  // Bad hexvalue had caused a hang in processTerm.
+  final input = r'''#a { color: #ebebeburl(0/IE8+9+); }''';
+  var stylesheet = parseCss(input, errors: errors, opts: optionErrors);
+
+  expect(stylesheet != null, true);
+  expect(errors.length, 3, reason: errors.toString());
+
+  var errorMessage = errors[0];
+  expect(errorMessage.message, contains('Bad hex number'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 0);
+  expect(errorMessage.span.start.column, 12);
+  expect(errorMessage.span.text, '#ebebeburl');
+
+  errorMessage = errors[1];
+  expect(errorMessage.message, contains('expected }, but found +'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 0);
+  expect(errorMessage.span.start.column, 30);
+  expect(errorMessage.span.text, '+');
+
+  errorMessage = errors[2];
+  expect(errorMessage.message, contains('premature end of file unknown CSS'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 0);
+  expect(errorMessage.span.start.column, 31);
+  expect(errorMessage.span.text, ')');
+
+  // Missing closing parenthesis for keyframes.
+  final input2 = r'''@-ms-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+''';
+
+  stylesheet = parseCss(input2, errors: errors..clear(), opts: optionErrors);
+
+  expect(stylesheet != null, true);
+
+  expect(errors.length, 1, reason: errors.toString());
+
+  errorMessage = errors[0];
+  expect(errorMessage.message, contains('unexpected end of file'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 7);
+  expect(errorMessage.span.start.column, 0);
+  expect(errorMessage.span.text, '');
+}
+
+main() {
+  test('Simple Terms', testSimpleTerms);
+  test('Declarations', testDeclarations);
+  test('Identifiers', testIdentifiers);
+  test('Composites', testComposites);
+  test('Units', testUnits);
+  test('Unicode', testUnicode);
+  test('Newer CSS', testNewerCss);
+  test('Media Queries', testMediaQueries);
+  test('Font-Face', testFontFace);
+  test('CSS file', testCssFile);
+  test('Compact Emitter', testCompactEmitter);
+  test('Selector Negation', testNotSelectors);
+  test('IE stuff', testIE);
+  test('IE declaration syntax', testIEDeclaration);
+  test('Hanging bugs', testHangs);
+}
diff --git a/pkg/csslib/test/error_test.dart b/pkg/csslib/test/error_test.dart
new file mode 100644
index 0000000..98acffc
--- /dev/null
+++ b/pkg/csslib/test/error_test.dart
@@ -0,0 +1,355 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library error_test;
+
+import 'package:unittest/unittest.dart';
+import 'testing.dart';
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'package:csslib/src/messages.dart';
+
+/**
+ * Test for unsupported font-weights values of bolder, lighter and inherit.
+ */
+void testUnsupportedFontWeights() {
+  var errors = [];
+
+  // TODO(terry): Need to support bolder.
+  // font-weight value bolder.
+  var input = ".foobar { font-weight: bolder; }";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:24: Unknown property value bolder
+.foobar { font-weight: bolder; }
+                       ^^^^^^''');
+  expect(stylesheet != null, true);
+
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  font-weight: bolder;
+}''');
+
+  // TODO(terry): Need to support lighter.
+  // font-weight value lighter.
+  input = ".foobar { font-weight: lighter; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:24: Unknown property value lighter
+.foobar { font-weight: lighter; }
+                       ^^^^^^^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  font-weight: lighter;
+}''');
+
+  // TODO(terry): Need to support inherit.
+  // font-weight value inherit.
+  input = ".foobar { font-weight: inherit; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:24: Unknown property value inherit
+.foobar { font-weight: inherit; }
+                       ^^^^^^^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  font-weight: inherit;
+}''');
+}
+
+/**
+ * Test for unsupported line-height values of units other than px, pt and
+ * inherit.
+ */
+void testUnsupportedLineHeights() {
+  var errors = [];
+
+  // line-height value in percentge unit.
+  var input = ".foobar { line-height: 120%; }";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:24: Unexpected value for line-height
+.foobar { line-height: 120%; }
+                       ^^^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  line-height: 120%;
+}''');
+
+  // TODO(terry): Need to support all units.
+  // line-height value in cm unit.
+  input = ".foobar { line-height: 20cm; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:24: Unexpected unit for line-height
+.foobar { line-height: 20cm; }
+                       ^^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  line-height: 20cm;
+}''');
+
+  // TODO(terry): Need to support inherit.
+  // line-height value inherit.
+  input = ".foobar { line-height: inherit; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:24: Unknown property value inherit
+.foobar { line-height: inherit; }
+                       ^^^^^^^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  line-height: inherit;
+}''');
+}
+
+/** Test for bad selectors. */
+void testBadSelectors() {
+  var errors = [];
+
+  // Invalid id selector.
+  var input = "# foo { color: #ff00ff; }";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:1: Not a valid ID selector expected #id
+# foo { color: #ff00ff; }
+^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+# foo {
+  color: #f0f;
+}''');
+
+  // Invalid class selector.
+  input = ". foo { color: #ff00ff; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:1: Not a valid class selector expected .className
+. foo { color: #ff00ff; }
+^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+. foo {
+  color: #f0f;
+}''');
+}
+
+/** Test for bad hex values. */
+void testBadHexValues() {
+  var errors = [];
+
+  // Invalid hex value.
+  var input = ".foobar { color: #AH787; }";
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:18: Bad hex number
+.foobar { color: #AH787; }
+                 ^^^^^^''');
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  color: #AH787;
+}''');
+
+  // Bad color constant.
+  input = ".foobar { color: redder; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:18: Unknown property value redder
+.foobar { color: redder; }
+                 ^^^^^^''');
+
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  color: redder;
+}''');
+
+  // Bad hex color #<space>ffffff.
+  input = ".foobar { color: # ffffff; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:18: Expected hex number
+.foobar { color: # ffffff; }
+                 ^''');
+
+  expect(stylesheet != null, true);
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  color: # ffffff;
+}''');
+
+  // Bad hex color #<space>123fff.
+  input = ".foobar { color: # 123fff; }";
+  stylesheet = parseCss(input, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:18: Expected hex number
+.foobar { color: # 123fff; }
+                 ^''');
+
+  expect(stylesheet != null, true);
+
+  // Formating is off with an extra space.  However, the entire value is bad
+  // and isn't processed anyway.
+  expect(prettyPrint(stylesheet), r'''
+.foobar {
+  color: # 123 fff;
+}''');
+
+}
+
+void testBadUnicode() {
+  var errors = [];
+  final String input = '''
+@font-face {
+  src: url(fonts/BBCBengali.ttf) format("opentype");
+  unicode-range: U+400-200;
+}''';
+
+  var stylesheet = parseCss(input, errors: errors);
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(),
+      'error :3:20: unicode first range can not be greater than last\n'
+      '  unicode-range: U+400-200;\n'
+      '                   ^^^^^^^');
+
+  final String input2 = '''
+@font-face {
+  src: url(fonts/BBCBengali.ttf) format("opentype");
+  unicode-range: U+12FFFF;
+}''';
+
+  stylesheet = parseCss(input2, errors: errors..clear());
+
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(),
+      'error :3:20: unicode range must be less than 10FFFF\n'
+      '  unicode-range: U+12FFFF;\n'
+      '                   ^^^^^^');
+}
+
+void testBadNesting() {
+  var errors = [];
+
+  // Test for bad declaration in a nested rule.
+  final String input = '''
+div {
+  width: 20px;
+  span + ul { color: blue; }
+  span + ul > #aaaa {
+    color: #ffghghgh;
+  }
+  background-color: red;
+}
+''';
+
+  var stylesheet = parseCss(input, errors: errors);
+  expect(errors.length, 1);
+  var errorMessage = messages.messages[0];
+  expect(errorMessage.message, contains('Bad hex number'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 4);
+  expect(errorMessage.span.start.column, 11);
+  expect(errorMessage.span.text, '#ffghghgh');
+
+  // Test for bad selector syntax.
+  final String input2 = '''
+div {
+  span + ul #aaaa > (3333)  {
+    color: #ffghghgh;
+  }
+}
+''';
+  var stylesheet2 = parseCss(input2, errors: errors..clear());
+  expect(errors.length, 4);
+  errorMessage = messages.messages[0];
+  expect(errorMessage.message, contains(':, but found +'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 1);
+  expect(errorMessage.span.start.column, 7);
+  expect(errorMessage.span.text, '+');
+
+  errorMessage = messages.messages[1];
+  expect(errorMessage.message, contains('Unknown property value ul'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 1);
+  expect(errorMessage.span.start.column, 9);
+  expect(errorMessage.span.text, 'ul');
+
+  errorMessage = messages.messages[2];
+  expect(errorMessage.message, contains('expected }, but found >'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 1);
+  expect(errorMessage.span.start.column, 18);
+  expect(errorMessage.span.text, '>');
+
+  errorMessage = messages.messages[3];
+  expect(errorMessage.message, contains('premature end of file unknown CSS'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 1);
+  expect(errorMessage.span.start.column, 20);
+  expect(errorMessage.span.text, '(');
+
+  // Test for missing close braces and bad declaration.
+  final String input3 = '''
+div {
+  span {
+    color: #green;
+}
+''';
+  var stylesheet3 = parseCss(input3, errors: errors..clear());
+  expect(errors.length, 2);
+  errorMessage = messages.messages[0];
+  expect(errorMessage.message, contains('Bad hex number'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 2);
+  expect(errorMessage.span.start.column, 11);
+  expect(errorMessage.span.text, '#green');
+
+  errorMessage = messages.messages[1];
+  expect(errorMessage.message, contains('expected }, but found end of file'));
+  expect(errorMessage.span, isNotNull);
+  expect(errorMessage.span.start.line, 3);
+  expect(errorMessage.span.start.column, 1);
+  expect(errorMessage.span.text, '\n');
+}
+
+main() {
+  test('font-weight value errors', testUnsupportedFontWeights);
+  test('line-height value errors', testUnsupportedLineHeights);
+  test('bad selectors', testBadSelectors);
+  test('bad Hex values', testBadHexValues);
+  test('bad unicode ranges', testBadUnicode);
+  test('nested rules', testBadNesting);
+}
diff --git a/pkg/csslib/test/nested_test.dart b/pkg/csslib/test/nested_test.dart
new file mode 100644
index 0000000..e6b0025
--- /dev/null
+++ b/pkg/csslib/test/nested_test.dart
@@ -0,0 +1,614 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library nested_test;
+
+import 'dart:utf';
+import 'package:unittest/unittest.dart';
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'testing.dart';
+
+List optionsCss = ['--no-colors', 'memory'];
+
+compileAndValidate(String input, String generated) {
+  var errors = [];
+  var stylesheet = compileCss(input, errors: errors, opts: optionsCss);
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+selectorVariations() {
+  final input1 = r'''html { color: red; }''';
+  final generated1 = r'''html {
+  color: #f00;
+}''';
+  compileAndValidate(input1, generated1);
+
+  final input2 = r'''button { span { height: 200 } }''';
+  final generated2 = r'''button {
+}
+button span {
+  height: 200;
+}''';
+  compileAndValidate(input2, generated2);
+
+  final input3 = r'''div { color: red; } button { span { height: 200 } }''';
+  final generated3 = r'''div {
+  color: #f00;
+}
+button {
+}
+button span {
+  height: 200;
+}''';
+  compileAndValidate(input3, generated3);
+
+  final input4 = r'''#header { color: red; h1 { font-size: 26px; } }''';
+  final generated4 = r'''#header {
+  color: #f00;
+}
+#header h1 {
+  font-size: 26px;
+}''';
+  compileAndValidate(input4, generated4);
+
+  final input5 = r'''
+#header {
+  color: red;
+  h1 { font-size: 26px; }
+  background-color: blue;
+}''';
+  final generated5 = r'''#header {
+  color: #f00;
+  background-color: #00f;
+}
+#header h1 {
+  font-size: 26px;
+}''';
+  compileAndValidate(input5, generated5);
+
+  final input6 = r'''html { body {color: red; }}''';
+  final generated6 = r'''html {
+}
+html body {
+  color: #f00;
+}''';
+  compileAndValidate(input6, generated6);
+
+  final input7 = r'''html body {color: red; }''';
+  final generated7 = r'''html body {
+  color: #f00;
+}''';
+  compileAndValidate(input7, generated7);
+
+  final input8 = r'''
+html, body { color: red; }
+button { height: 200 }
+body { width: 300px; }''';
+  final generated8 = r'''html, body {
+  color: #f00;
+}
+button {
+  height: 200;
+}
+body {
+  width: 300px;
+}''';
+  compileAndValidate(input8, generated8);
+
+  final input9 = '''
+html, body {
+  color: red;
+  button { height: 200 }
+  div { width: 300px; }
+}''';
+  final generated9 = r'''html, body {
+  color: #f00;
+}
+html button, body button {
+  height: 200;
+}
+html div, body div {
+  width: 300px;
+}''';
+  compileAndValidate(input9, generated9);
+
+  final input10 = '''
+html {
+  color: red;
+  button, div { height: 200 }
+  body { width: 300px; }
+}''';
+  final generated10 = r'''html {
+  color: #f00;
+}
+html button, html div {
+  height: 200;
+}
+html body {
+  width: 300px;
+}''';
+  compileAndValidate(input10, generated10);
+
+  final input11 = '''
+html, body {
+  color: red;
+  button, div { height: 200 }
+  table { width: 300px; }
+}''';
+  final generated11 = r'''html, body {
+  color: #f00;
+}
+html button, body button, html div, body div {
+  height: 200;
+}
+html table, body table {
+  width: 300px;
+}''';
+  compileAndValidate(input11, generated11);
+
+  final input12 = '''
+html, body {
+  color: red;
+  button, div {
+    span, a, ul { height: 200 }
+  }
+  table { width: 300px; }
+}''';
+  final generated12 = r'''html, body {
+  color: #f00;
+}
+'''
+'html button span, body button span, html div span, body div span, '
+'html button a, body button a, html div a, body div a, html button ul, '
+r'''body button ul, html div ul, body div ul {
+  height: 200;
+}
+html table, body table {
+  width: 300px;
+}''';
+  compileAndValidate(input12, generated12);
+
+  final input13 = r'''
+#header {
+  div {
+  width: 100px;
+  a { height: 200px; }
+  }
+  color: blue;
+}
+span { color: #1f1f1f; }
+''';
+  final generated13 = r'''#header {
+  color: #00f;
+}
+#header div {
+  width: 100px;
+}
+#header div a {
+  height: 200px;
+}
+span {
+  color: #1f1f1f;
+}''';
+  compileAndValidate(input13, generated13);
+}
+
+void simpleNest() {
+  final errors = [];
+  final input = '''
+div span { color: green; }
+#header {
+  color: red;
+  h1 {
+    font-size: 26px;
+    font-weight: bold;
+  }
+  p {
+    font-size: 12px;
+    a {
+      text-decoration: none;
+    }
+  }
+  background-color: blue;
+}
+div > span[attr="foo"] { color: yellow; }
+''';
+
+  final generated =
+r'''div span {
+  color: #008000;
+}
+#header {
+  color: #f00;
+  background-color: #00f;
+}
+#header h1 {
+  font-size: 26px;
+  font-weight: bold;
+}
+#header p {
+  font-size: 12px;
+}
+#header p a {
+  text-decoration: none;
+}
+div > span[attr="foo"] {
+  color: #ff0;
+}''';
+  compileAndValidate(input, generated);
+}
+
+void complexNest() {
+  final errors = [];
+  final input = '''
+@font-face  { font-family: arial; }
+div { color: #f0f0f0; }
+#header + div {
+  color: url(abc.png);
+  *[attr="bar"] {
+    font-size: 26px;
+    font-weight: bold;
+  }
+  p~ul {
+    font-size: 12px;
+    :not(p) {
+      text-decoration: none;
+      div > span[attr="foo"] { color: yellow; }
+    }
+  }
+  background-color: blue;
+  span {
+    color: red;
+    .one { color: blue; }
+    .two { color: green; }
+    .three { color: yellow; }
+    .four {
+       .four-1 { background-color: #00000f; }
+       .four-2 { background-color: #0000ff; }
+       .four-3 { background-color: #000fff; }
+       .four-4 {
+         height: 44px;
+         .four-4-1 { height: 10px; }
+         .four-4-2 { height: 20px; }
+         .four-4-3 { height: 30px; }
+         width: 44px;
+       }
+    }
+  }
+}
+span { color: #1f1f2f; }
+''';
+
+  final generated = r'''@font-face  {
+  font-family: arial;
+}
+div {
+  color: #f0f0f0;
+}
+#header + div {
+  color: url("abc.png");
+  background-color: #00f;
+}
+#header + div *[attr="bar"] {
+  font-size: 26px;
+  font-weight: bold;
+}
+#header + div p ~ ul {
+  font-size: 12px;
+}
+#header + div p ~ ul :not(p) {
+  text-decoration: none;
+}
+#header + div p ~ ul :not(p) div > span[attr="foo"] {
+  color: #ff0;
+}
+#header + div span {
+  color: #f00;
+}
+#header + div span .one {
+  color: #00f;
+}
+#header + div span .two {
+  color: #008000;
+}
+#header + div span .three {
+  color: #ff0;
+}
+#header + div span .four .four-1 {
+  background-color: #00000f;
+}
+#header + div span .four .four-2 {
+  background-color: #00f;
+}
+#header + div span .four .four-3 {
+  background-color: #000fff;
+}
+#header + div span .four .four-4 {
+  height: 44px;
+  width: 44px;
+}
+#header + div span .four .four-4 .four-4-1 {
+  height: 10px;
+}
+#header + div span .four .four-4 .four-4-2 {
+  height: 20px;
+}
+#header + div span .four .four-4 .four-4-3 {
+  height: 30px;
+}
+span {
+  color: #1f1f2f;
+}''';
+
+  compileAndValidate(input, generated);
+}
+
+void mediaNesting() {
+  var errors = [];
+
+  final input = r'''
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+  #toggle-all {
+    image: url(test.jpb);
+    div, table {
+      background: none;
+      a { width: 100px; }
+    }
+    color: red;
+  }
+}
+''';
+  final generated = r'''@media screen AND (-webkit-min-device-pixel-ratio:0) {
+#toggle-all {
+  image: url("test.jpb");
+  color: #f00;
+}
+#toggle-all div, #toggle-all table {
+  background: none;
+}
+#toggle-all div a, #toggle-all table a {
+  width: 100px;
+}
+}''';
+
+  compileAndValidate(input, generated);
+}
+
+void simpleThis() {
+  final errors = [];
+  final input = '''#header {
+  h1 {
+    font-size: 26px;
+    font-weight: bold;
+  }
+  p { font-size: 12px;
+    a { text-decoration: none;
+      &:hover { border-width: 1px }
+    }
+  }
+}
+''';
+
+  final generated = r'''#header {
+}
+#header h1 {
+  font-size: 26px;
+  font-weight: bold;
+}
+#header p {
+  font-size: 12px;
+}
+#header p a {
+  text-decoration: none;
+}
+#header p a:hover {
+  border-width: 1px;
+}''';
+
+  compileAndValidate(input, generated);
+}
+
+void complexThis() {
+  var errors = [];
+
+  final input1 = r'''
+.light {
+  .leftCol {
+    .textLink {
+      color: fooL1;
+      &:hover { color: barL1;}
+    } 
+    .picLink {
+      background-image: url(/fooL1.jpg);
+      &:hover { background-image: url(/barL1.jpg);}
+    }
+    .textWithIconLink {
+      color: fooL2;
+      background-image: url(/fooL2.jpg);
+      &:hover { color: barL2; background-image: url(/barL2.jpg);}
+    }
+  }   
+}''';
+
+  final generated1 = r'''.light {
+}
+.light .leftCol .textLink {
+  color: fooL1;
+}
+.light .leftCol .textLink:hover {
+  color: barL1;
+}
+.light .leftCol .picLink {
+  background-image: url("/fooL1.jpg");
+}
+.light .leftCol .picLink:hover {
+  background-image: url("/barL1.jpg");
+}
+.light .leftCol .textWithIconLink {
+  color: fooL2;
+  background-image: url("/fooL2.jpg");
+}
+.light .leftCol .textWithIconLink:hover {
+  color: barL2;
+  background-image: url("/barL2.jpg");
+}''';
+
+  compileAndValidate(input1, generated1);
+
+  final input2 = r'''
+.textLink {
+  .light .leftCol & {
+    color: fooL1;
+    &:hover { color: barL1; }
+  }      
+  .light .rightCol & {
+    color: fooL3;
+    &:hover { color: barL3; }
+  } 
+}''';
+
+  final generated2 = r'''
+.textLink {
+}
+.light .leftCol .textLink {
+  color: fooL1;
+}
+.light .leftCol .textLink:hover {
+  color: barL1;
+}
+.light .rightCol .textLink {
+  color: fooL3;
+}
+.light .rightCol .textLink:hover {
+  color: barL3;
+}''';
+
+  compileAndValidate(input2, generated2);
+}
+
+variationsThis() {
+  var errors = [];
+
+  final input1 = r'''
+.textLink {
+  a {
+    light .leftCol & {
+      color: red;
+    }
+  }
+}''';
+  final generated1 = r'''.textLink {
+}
+light .leftCol .textLink a {
+  color: #f00;
+}''';
+
+  compileAndValidate(input1, generated1);
+
+  final input2 = r'''.textLink {
+  a {
+    & light .leftCol & {
+      color: red;
+    }
+  }
+}''';
+  final generated2 = r'''.textLink {
+}
+.textLink a light .leftCol .textLink a {
+  color: #f00;
+}''';
+  compileAndValidate(input2, generated2);
+
+  final input3 = r'''
+.textLink {
+  a {
+    & light .leftCol { color: red; }
+  }
+}''';
+  final generated3 = r'''.textLink {
+}
+.textLink a light .leftCol {
+  color: #f00;
+}''';
+  compileAndValidate(input3, generated3);
+
+  final input4 = r'''
+.textLink {
+  a {
+    & light .leftCol { color: red; }
+    &:hover { width: 100px; }
+  }
+}''';
+  final generated4 = r'''.textLink {
+}
+.textLink a light .leftCol {
+  color: #f00;
+}
+.textLink a:hover {
+  width: 100px;
+}''';
+  compileAndValidate(input4, generated4);
+
+  final input5 = r'''.textLink { a { &:hover { color: red; } } }''';
+  final generated5 = r'''.textLink {
+}
+.textLink a:hover {
+  color: #f00;
+}''';
+
+  compileAndValidate(input5, generated5);
+
+  final input6 = r'''.textLink { &:hover { color: red; } }''';
+  final generated6 = r'''.textLink {
+}
+.textLink:hover {
+  color: #f00;
+}''';
+  compileAndValidate(input6, generated6);
+
+  final input7 = r'''.textLink { a { & + & { color: red; } } }''';
+  final generated7 = r'''.textLink {
+}
+.textLink a + .textLink a {
+  color: #f00;
+}''';
+  compileAndValidate(input7, generated7);
+
+  final input8 = r'''.textLink { a { & { color: red; } } }''';
+  final generated8 = r'''.textLink {
+}
+.textLink a {
+  color: #f00;
+}''';
+  compileAndValidate(input8, generated8);
+
+  final input9 = r'''.textLink { a { & ~ & { color: red; } } }''';
+  final generated9 = r'''.textLink {
+}
+.textLink a ~ .textLink a {
+  color: #f00;
+}''';
+  compileAndValidate(input9, generated9);
+
+  final input10 = r'''.textLink { a { & & { color: red; } } }''';
+  final generated10 = r'''.textLink {
+}
+.textLink a .textLink a {
+  color: #f00;
+}''';
+  compileAndValidate(input10, generated10);
+}
+
+main() {
+  test('Selector and Nested Variations', selectorVariations);
+  test('Simple nesting', simpleNest);
+  test('Complex nesting', complexNest);
+  test('@media nesting', mediaNesting);
+  test('Simple &', simpleThis);
+  test("Variations &", variationsThis);
+  test('Complex &', complexThis);
+}
diff --git a/pkg/csslib/test/run.sh b/pkg/csslib/test/run.sh
new file mode 100755
index 0000000..7d26209
--- /dev/null
+++ b/pkg/csslib/test/run.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Usage: call directly in the commandline as test/run.sh ensuring that you have
+# 'dart' in your path. Filter tests by passing a pattern as an argument to this
+# script.
+
+# TODO(sigmund): replace with a real test runner
+
+# bail on error
+set -e
+
+# print commands executed by this script
+# set -x
+
+DIR=$( cd $( dirname "${BASH_SOURCE[0]}" ) && pwd )
+DART_FLAGS="--checked"
+TEST_PATTERN=$1
+
+if [[ ($TEST_PATTERN == "") ]]; then
+  # Note: dart_analyzer needs to be run from the root directory for proper path
+  # canonicalization.
+  pushd $DIR/.. &>/dev/null
+  echo Analyzing compiler for warnings or type errors
+  dartanalyzer --fatal-warnings --fatal-type-errors bin/css.dart
+  popd &>/dev/null
+fi
+ 
+pushd $DIR &>/dev/null
+if [[ ($TEST_PATTERN == "canary") || ($TEST_PATTERN = "") ]]; then
+  dart $DART_FLAGS run_all.dart
+else
+  dart $DART_FLAGS run_all.dart $TEST_PATTERN
+fi
+popd &>/dev/null
+
+echo All tests completed.
diff --git a/pkg/csslib/test/run_all.dart b/pkg/csslib/test/run_all.dart
new file mode 100644
index 0000000..517d5a0
--- /dev/null
+++ b/pkg/csslib/test/run_all.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * This is a helper for run.sh. We try to run all of the Dart code in one
+ * instance of the Dart VM to reduce warm-up time.
+ */
+library run_impl;
+
+import 'dart:io';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/compact_vm_config.dart';
+import 'testing.dart';
+
+import 'compiler_test.dart' as compiler_test;
+import 'declaration_test.dart' as declaration_test;
+import 'var_test.dart' as var_test;
+import 'nested_test.dart' as nested_test;
+import 'error_test.dart' as error_test;
+import 'selector_test.dart' as selector_test;
+import 'visitor_test.dart' as visitor_test;
+
+main() {
+  var args = new Options().arguments;
+
+  var pattern = new RegExp(args.length > 0 ? args[0] : '.');
+
+  useCompactVMConfiguration();
+  useMockMessages();
+
+  if (pattern.hasMatch('compiler_test.dart')) compiler_test.main();
+  if (pattern.hasMatch('declaration_test.dart')) declaration_test.main();
+  if (pattern.hasMatch('var_test.dart')) var_test.main();
+  if (pattern.hasMatch('nested_test.dart')) nested_test.main();
+  if (pattern.hasMatch('selector_test.dart')) selector_test.main();
+  if (pattern.hasMatch('visitor_test.dart')) visitor_test.main();
+  if (pattern.hasMatch('error_test.dart')) error_test.main();
+}
diff --git a/pkg/csslib/test/selector_test.dart b/pkg/csslib/test/selector_test.dart
new file mode 100644
index 0000000..ad015bb
--- /dev/null
+++ b/pkg/csslib/test/selector_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library selector_test;
+
+import 'package:unittest/unittest.dart';
+import 'testing.dart';
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+
+void testSelectorSuccesses() {
+  var errors = [];
+  var selectorAst = selector('#div .foo', errors: errors);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('#div .foo', compactOuptut(selectorAst));
+
+  // Valid selectors for class names.
+  selectorAst = selector('.foo', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('.foo', compactOuptut(selectorAst));
+
+  selectorAst = selector('.foobar .xyzzy', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('.foobar .xyzzy', compactOuptut(selectorAst));
+
+  selectorAst = selector('.foobar .a-story .xyzzy', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('.foobar .a-story .xyzzy', compactOuptut(selectorAst));
+
+  selectorAst = selector('.foobar .xyzzy .a-story .b-story',
+      errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('.foobar .xyzzy .a-story .b-story', compactOuptut(selectorAst));
+
+  // Valid selectors for element IDs.
+  selectorAst = selector('#id1', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('#id1', compactOuptut(selectorAst));
+
+  selectorAst = selector('#id-number-3', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('#id-number-3', compactOuptut(selectorAst));
+
+  selectorAst = selector('#_privateId', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect('#_privateId', compactOuptut(selectorAst));
+}
+
+// TODO(terry): Move this failure case to a failure_test.dart when the analyzer
+//              and validator exit then they'll be a bunch more checks.
+void testSelectorFailures() {
+  var errors = [];
+
+  // Test for invalid class name (can't start with number).
+  var selectorAst = selector('.foobar .1a-story .xyzzy', errors: errors);
+  expect(errors.isEmpty, false);
+  expect(errors[0].toString(), r'''
+error :1:9: name must start with a alpha character, but found a number
+.foobar .1a-story .xyzzy
+        ^^''');
+}
+
+main() {
+  test('Valid Selectors', testSelectorSuccesses);
+  test('Invalid Selectors', testSelectorFailures);
+}
diff --git a/pkg/csslib/test/testing.dart b/pkg/csslib/test/testing.dart
new file mode 100644
index 0000000..e7b14bd
--- /dev/null
+++ b/pkg/csslib/test/testing.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Common definitions used for setting up the test environment. */
+library testing;
+
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'package:csslib/src/messages.dart';
+
+useMockMessages() {
+  messages = new Messages(printHandler: (message) {});
+}
+
+/**
+ * Spin-up CSS parser in checked mode to detect any problematic CSS.  Normally,
+ * CSS will allow any property/value pairs regardless of validity; all of our
+ * tests (by default) will ensure that the CSS is really valid.
+ */
+StyleSheet parseCss(String cssInput, {List errors, List opts}) =>
+  parse(cssInput, errors: errors, options: opts == null ?
+      ['--no-colors', '--checked', '--warnings_as_errors', 'memory'] : opts);
+
+/**
+ * Spin-up CSS parser in checked mode to detect any problematic CSS.  Normally,
+ * CSS will allow any property/value pairs regardless of validity; all of our
+ * tests (by default) will ensure that the CSS is really valid.
+ */
+StyleSheet compileCss(String cssInput, {List errors, List opts}) =>
+  compile(cssInput, errors: errors, options: opts == null ?
+      ['--no-colors', '--checked', '--warnings_as_errors', 'memory'] : opts);
+
+/** CSS emitter walks the style sheet tree and emits readable CSS. */
+var _emitCss = new CssPrinter();
+
+/** Simple Visitor does nothing but walk tree. */
+var _cssVisitor = new Visitor();
+
+/** Pretty printer for CSS. */
+String prettyPrint(StyleSheet ss) {
+  // Walk the tree testing basic Vistor class.
+  walkTree(ss);
+  return (_emitCss..visitTree(ss, pretty: true)).toString();
+}
+
+/**
+ * Helper function to emit compact (non-pretty printed) CSS for suite test
+ * comparsions.  Spaces, new lines, etc. are reduced for easier comparsions of
+ * expected suite test results.
+ */
+String compactOuptut(StyleSheet ss) {
+  walkTree(ss);
+  return (_emitCss..visitTree(ss, pretty: false)).toString();
+}
+
+/** Walks the style sheet tree does nothing; insures the basic walker works. */
+void walkTree(StyleSheet ss) {
+  _cssVisitor..visitTree(ss);
+}
+
+String dumpTree(StyleSheet ss) => treeToDebugString(ss);
+
+
diff --git a/pkg/csslib/test/var_test.dart b/pkg/csslib/test/var_test.dart
new file mode 100644
index 0000000..fb870c7
--- /dev/null
+++ b/pkg/csslib/test/var_test.dart
@@ -0,0 +1,629 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library var_test;
+
+import 'dart:utf';
+import 'package:unittest/unittest.dart';
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'testing.dart';
+
+void simpleVar() {
+  final errors = [];
+  final input = ''':root {
+  var-color-background: red;
+  var-color-foreground: blue;
+
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #00ff00;
+}
+.testIt {
+  color: var(color-foreground);
+  background: var(color-background);
+}
+''';
+
+  final generated = ''':root {
+  var-color-background: #f00;
+  var-color-foreground: #00f;
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #0f0;
+}
+.testIt {
+  color: var(color-foreground);
+  background: var(color-background);
+}''';
+
+  var stylesheet = compileCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void expressionsVar() {
+  final errors = [];
+  final input = ''':root {
+  var-color-background: red;
+  var-color-foreground: blue;
+
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #00ff00;
+
+  var-image: url(test.png);
+
+  var-b-width: 20cm;
+  var-m-width: 33%;
+  var-b-height: 30EM;
+  var-width: .6in;
+  var-length: 1.2in;
+  var-web-stuff: -10Px;
+  var-rgba: rgba(10,20,255);
+  var-transition: color 0.4s;
+  var-transform: rotate(20deg);
+  var-content: "✔";
+  var-text-shadow: 0 -1px 0 #bfbfbf;
+  var-font-family: Gentium;
+  var-src: url("http://example.com/fonts/Gentium.ttf");
+  var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+  var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+  var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+  var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+
+.testIt {
+  color: var(color-foreground);
+  background: var(c);
+  background-image: var(image);
+
+  border-width: var(b-width);
+  margin-width: var(m-width);
+  border-height: var(b-height);
+  width: var(width);
+  length: var(length);
+  -web-stuff: var(web-stuff);
+  background-color: var(rgba);
+
+  transition: var(transition);
+  transform: var(transform);
+  content: var(content);
+  text-shadow: var(text-shadow);
+}
+
+@font-face {
+  font-family: var(font-family);
+  src: var(src);
+  unicode-range: var(unicode-range);
+}
+
+@font-face {
+  font-family: var(font-family);
+  src: var(src-1);
+  unicode-range: var(unicode-range-1);
+}
+
+.foobar {
+    grid-columns: var(grid-columns);
+}
+''';
+
+  final generated = ''':root {
+  var-color-background: #f00;
+  var-color-foreground: #00f;
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #0f0;
+  var-image: url("test.png");
+  var-b-width: 20cm;
+  var-m-width: 33%;
+  var-b-height: 30em;
+  var-width: .6in;
+  var-length: 1.2in;
+  var-web-stuff: -10px;
+  var-rgba: rgba(10, 20, 255);
+  var-transition: color 0.4s;
+  var-transform: rotate(20deg);
+  var-content: "✔";
+  var-text-shadow: 0 -1px 0 #bfbfbf;
+  var-font-family: Gentium;
+  var-src: url("http://example.com/fonts/Gentium.ttf");
+  var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+  var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+  var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+  var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+.testIt {
+  color: var(color-foreground);
+  background: var(c);
+  background-image: var(image);
+  border-width: var(b-width);
+  margin-width: var(m-width);
+  border-height: var(b-height);
+  width: var(width);
+  length: var(length);
+  -web-stuff: var(web-stuff);
+  background-color: var(rgba);
+  transition: var(transition);
+  transform: var(transform);
+  content: var(content);
+  text-shadow: var(text-shadow);
+}
+@font-face  {
+  font-family: var(font-family);
+  src: var(src);
+  unicode-range: var(unicode-range);
+}
+@font-face  {
+  font-family: var(font-family);
+  src: var(src-1);
+  unicode-range: var(unicode-range-1);
+}
+.foobar {
+  grid-columns: var(grid-columns);
+}''';
+
+  var stylesheet = compileCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void defaultVar() {
+  final errors = [];
+  final input = '''
+:root {
+  var-color-background: red;
+  var-color-foreground: blue;
+
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #00ff00;
+
+  var-image: url(test.png);
+
+  var-b-width: 20cm;
+  var-m-width: 33%;
+  var-b-height: 30EM;
+}
+
+.test {
+  background-color: var(test, orange);
+}
+
+body {
+  background: var(a) var(image) no-repeat right top;
+}
+
+div {
+  background: var(color-background) url('img_tree.png') no-repeat right top;
+}
+
+.test-2 {
+  background: var(color-background) var(image-2, url('img_1.png')) 
+              no-repeat right top;
+}
+
+.test-3 {
+  background: var(color-background) var(image-2) no-repeat right top;
+}
+
+.test-4 {
+  background: #ffff00 var(image) no-repeat right top;
+}
+
+.test-5 {
+  background: var(test-color, var(a)) var(image) no-repeat right top;
+}
+
+.test-6 {
+  border: red var(a-1, solid 20px);
+}
+''';
+
+  final generated = ''':root {
+  var-color-background: #f00;
+  var-color-foreground: #00f;
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #0f0;
+  var-image: url("test.png");
+  var-b-width: 20cm;
+  var-m-width: 33%;
+  var-b-height: 30em;
+}
+.test {
+  background-color: var(test, #ffa500);
+}
+body {
+  background: var(a) var(image) no-repeat right top;
+}
+div {
+  background: var(color-background) url("img_tree.png") no-repeat right top;
+}
+.test-2 {
+  background: var(color-background) var(image-2, url("img_1.png")) no-repeat right top;
+}
+.test-3 {
+  background: var(color-background) var(image-2) no-repeat right top;
+}
+.test-4 {
+  background: #ff0 var(image) no-repeat right top;
+}
+.test-5 {
+  background: var(test-color, var(a)) var(image) no-repeat right top;
+}
+.test-6 {
+  border: #f00 var(a-1, solid 20px);
+}''';
+
+  var stylesheet = compileCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+void cyclesVar() {
+  final errors = [];
+  final input = ''':root {
+  var-color-background: red;
+  var-color-foreground: blue;
+
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #00ff00;
+
+  var-one: var(two);
+  var-two: var(one);
+
+  var-four: var(five);
+  var-five: var(six);
+  var-six: var(four);
+
+  var-def-1: var(def-2);
+  var-def-2: var(def-3);
+  var-def-3: var(def-2);
+}
+.testIt {
+  color: var(color-foreground);
+  background: var(color-background);
+}
+.test-2 {
+  color: var(one);
+}
+''';
+
+  final generated = ''':root {
+  var-color-background: #f00;
+  var-color-foreground: #00f;
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #0f0;
+}
+.testIt {
+  color: var(color-foreground);
+  background: var(color-background);
+}
+.test-2 {
+  color: var(one);
+}''';
+
+  var stylesheet = compileCss(input, errors: errors,
+      opts: ['--no-colors', '--warnings_as_errors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.length, 8, reason: errors.toString());
+  expect(errors[0].toString(),
+      'error :14:3: var cycle detected var-six\n'
+      '  var-six: var(four);\n'
+      '  ^^^^^^^^^^^^^^^^^^');
+  expect(errors[1].toString(),
+      'error :18:3: var cycle detected var-def-3\n'
+      '  var-def-3: var(def-2);\n'
+      '  ^^^^^^^^^^^^^^^^^^^^^');
+  expect(errors[2].toString(),
+      'error :10:3: var cycle detected var-two\n'
+      '  var-two: var(one);\n'
+      '  ^^^^^^^^^^^^^^^^^');
+  expect(errors[3].toString(),
+      'error :17:3: var cycle detected var-def-2\n'
+      '  var-def-2: var(def-3);\n'
+      '  ^^^^^^^^^^^^^^^^^^^^^');
+  expect(errors[4].toString(),
+      'error :16:3: var cycle detected var-def-1\n'
+      '  var-def-1: var(def-2);\n'
+      '  ^^^^^^^^^^^^^^^^^^^^^');
+  expect(errors[5].toString(),
+      'error :13:3: var cycle detected var-five\n'
+      '  var-five: var(six);\n'
+      '  ^^^^^^^^^^^^^^^^^^');
+  expect(errors[6].toString(),
+      'error :9:3: var cycle detected var-one\n'
+      '  var-one: var(two);\n'
+      '  ^^^^^^^^^^^^^^^^^');
+  expect(errors[7].toString(),
+      'error :12:3: var cycle detected var-four\n'
+      '  var-four: var(five);\n'
+      '  ^^^^^^^^^^^^^^^^^^^');
+  expect(prettyPrint(stylesheet), generated);
+}
+
+parserVar() {
+  final errors = [];
+  final input = ''':root {
+  var-color-background: red;
+  var-color-foreground: blue;
+
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #00ff00;
+
+  var-image: url(test.png);
+
+  var-b-width: 20cm;
+  var-m-width: 33%;
+  var-b-height: 30EM;
+  var-width: .6in;
+  var-length: 1.2in;
+  var-web-stuff: -10Px;
+  var-rgba: rgba(10,20,255);
+  var-transition: color 0.4s;
+  var-transform: rotate(20deg);
+  var-content: "✔";
+  var-text-shadow: 0 -1px 0 #bfbfbf;
+  var-font-family: Gentium;
+  var-src: url("http://example.com/fonts/Gentium.ttf");
+  var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+  var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+  var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+  var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+
+.testIt {
+  color: var(color-foreground);
+  background: var(c);
+  background-image: var(image);
+
+  border-width: var(b-width);
+  margin-width: var(m-width);
+  border-height: var(b-height);
+  width: var(width);
+  length: var(length);
+  -web-stuff: var(web-stuff);
+  background-color: var(rgba);
+
+  transition: var(transition);
+  transform: var(transform);
+  content: var(content);
+  text-shadow: var(text-shadow);
+}
+
+@font-face {
+  font-family: var(font-family);
+  src: var(src);
+  unicode-range: var(unicode-range);
+}
+
+@font-face {
+  font-family: var(font-family);
+  src: var(src-1);
+  unicode-range: var(unicode-range-1);
+}
+
+.foobar {
+    grid-columns: var(grid-columns);
+}
+''';
+
+  final generated = ''':root {
+  var-color-background: #f00;
+  var-color-foreground: #00f;
+  var-a: var(b);
+  var-b: var(c);
+  var-c: #0f0;
+  var-image: url("test.png");
+  var-b-width: 20cm;
+  var-m-width: 33%;
+  var-b-height: 30em;
+  var-width: .6in;
+  var-length: 1.2in;
+  var-web-stuff: -10px;
+  var-rgba: rgba(10, 20, 255);
+  var-transition: color 0.4s;
+  var-transform: rotate(20deg);
+  var-content: "✔";
+  var-text-shadow: 0 -1px 0 #bfbfbf;
+  var-font-family: Gentium;
+  var-src: url("http://example.com/fonts/Gentium.ttf");
+  var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+  var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+  var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+  var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+.testIt {
+  color: var(color-foreground);
+  background: var(c);
+  background-image: var(image);
+  border-width: var(b-width);
+  margin-width: var(m-width);
+  border-height: var(b-height);
+  width: var(width);
+  length: var(length);
+  -web-stuff: var(web-stuff);
+  background-color: var(rgba);
+  transition: var(transition);
+  transform: var(transform);
+  content: var(content);
+  text-shadow: var(text-shadow);
+}
+@font-face  {
+  font-family: var(font-family);
+  src: var(src);
+  unicode-range: var(unicode-range);
+}
+@font-face  {
+  font-family: var(font-family);
+  src: var(src-1);
+  unicode-range: var(unicode-range-1);
+}
+.foobar {
+  grid-columns: var(grid-columns);
+}''';
+
+  var stylesheet = parseCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+testVar() {
+  final errors = [];
+  final input = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+  background-color: var(color-background);
+  color: var(color-foreground);
+}
+''';
+  final generated = '''
+var-color-background: #f00;
+var-color-foreground: #00f;
+
+.test {
+  background-color: var(color-background);
+  color: var(color-foreground);
+}''';
+
+  var stylesheet = parseCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  stylesheet = compileCss(input, errors: errors..clear(),
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  final input2 = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+  background-color: @color-background;
+  color: @color-foreground;
+}
+''';
+  final generated2 = '''var-color-background: #f00;
+var-color-foreground: #00f;
+
+.test {
+  background-color: var(color-background);
+  color: var(color-foreground);
+}''';
+
+  stylesheet = parseCss(input, errors: errors..clear(),
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated2);
+
+  stylesheet = compileCss(input2, errors: errors..clear(),
+      opts: ['--no-colors', 'memory', '--no-less']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated2);
+}
+
+testLess() {
+  final errors = [];
+  final input = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+  background-color: var(color-background);
+  color: var(color-foreground);
+}
+''';
+  final generated = '''var-color-background: #f00;
+var-color-foreground: #00f;
+
+.test {
+  background-color: var(color-background);
+  color: var(color-foreground);
+}''';
+
+  var stylesheet = parseCss(input, errors: errors,
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  stylesheet = compileCss(input, errors: errors..clear(),
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+
+  final input2 = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+  background-color: @color-background;
+  color: @color-foreground;
+}
+''';
+  final generated2 = '''var-color-background: #f00;
+var-color-foreground: #00f;
+
+.test {
+  background-color: var(color-background);
+  color: var(color-foreground);
+}''';
+
+  stylesheet = parseCss(input, errors: errors..clear(),
+      opts: ['--no-colors', 'memory']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated2);
+
+  stylesheet = compileCss(input2, errors: errors..clear(),
+      opts: ['--no-colors', 'memory', '--no-less']);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated2);
+}
+
+main() {
+  test('Simple var', simpleVar);
+  test('Expressions var', expressionsVar);
+  test('Default value in var()', defaultVar);
+  test('CSS Parser only var', parserVar);
+  test('Var syntax', testVar);
+  test('Cycles var', cyclesVar);
+  test('Less syntax', testLess);
+}
diff --git a/pkg/csslib/test/visitor_test.dart b/pkg/csslib/test/visitor_test.dart
new file mode 100644
index 0000000..e60dbc5
--- /dev/null
+++ b/pkg/csslib/test/visitor_test.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library visitor_test;
+
+import 'dart:utf';
+import 'package:unittest/unittest.dart';
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'testing.dart';
+
+class ClassVisitor extends Visitor {
+  final List expectedClasses;
+  final Set<String> foundClasses = new Set();
+
+  ClassVisitor(this.expectedClasses);
+
+  void visitClassSelector(ClassSelector node) {
+    foundClasses.add(node.name);
+  }
+
+  bool get matches {
+    bool match = true;
+    foundClasses.forEach((value) {
+      match = match && expectedClasses.contains(value);
+    });
+    expectedClasses.forEach((value) {
+      match = match && foundClasses.contains(value);
+    });
+
+    return match;
+  }
+}
+
+void testClassVisitors() {
+  var errors = [];
+  var in1 = '.foobar { }';
+
+  var s = parseCss(in1, errors: errors);
+
+  expect(s != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  var clsVisits = new ClassVisitor(['foobar'])..visitTree(s);
+  expect(clsVisits.matches, true);
+
+  in1= '''
+      .foobar1 { }
+      .xyzzy .foo #my-div { color: red; }
+      div.hello { font: arial; }
+    ''';
+
+  s = parseCss(in1, errors: errors..clear(), opts: ['--no-colors', 'memory']);
+
+  expect(s != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  clsVisits =
+      new ClassVisitor(['foobar1', 'xyzzy', 'foo', 'hello'])..visitTree(s);
+  expect(clsVisits.matches, true);
+
+  expect(prettyPrint(s), r'''
+.foobar1 {
+}
+.xyzzy .foo #my-div {
+  color: #f00;
+}
+div.hello {
+  font: arial;
+}''');
+}
+
+class PolyfillEmitter extends CssPrinter {
+  final String _prefix;
+
+  PolyfillEmitter(this._prefix);
+
+  void visitClassSelector(ClassSelector node) {
+    emit('.${_prefix}_${node.name}');
+  }
+}
+
+String polyfillPrint(String prefix, StyleSheet ss) =>
+  (new PolyfillEmitter(prefix)..visitTree(ss, pretty: true)).toString();
+
+void testPolyFill() {
+  var errors = [];
+  final input = r'''
+.foobar { }
+div.xyzzy { }
+#foo .foo .bar .foobar { }
+''';
+
+  final generated = r'''
+.myComponent_foobar {
+}
+div.myComponent_xyzzy {
+}
+#foo .myComponent_foo .myComponent_bar .myComponent_foobar {
+}''';
+
+  var s = parseCss(input, errors: errors);
+  expect(s != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+
+  final emitted = polyfillPrint('myComponent', s);
+  expect(emitted, generated);
+}
+
+main() {
+  test('Class Visitors', testClassVisitors);
+  test('Polyfill', testPolyFill);
+}
diff --git a/pkg/custom_element/lib/custom_element.dart b/pkg/custom_element/lib/custom_element.dart
index 010b392..16978ae 100644
--- a/pkg/custom_element/lib/custom_element.dart
+++ b/pkg/custom_element/lib/custom_element.dart
@@ -86,9 +86,9 @@
     initCustomElements(c);
   }
   if (node is Element) {
-    var ctor = _customElements[node.localName];
+    var ctor = _customElements[(node as Element).localName];
     if (ctor == null) {
-      var attr = node.attributes['is'];
+      var attr = (node as Element).attributes['is'];
       if (attr != null) ctor = _customElements[attr];
     }
     if (ctor != null) _initCustomElement(node, ctor);
diff --git a/pkg/docgen/README.md b/pkg/docgen/README.md
index 0e3b3da..1af9ebe 100644
--- a/pkg/docgen/README.md
+++ b/pkg/docgen/README.md
@@ -37,6 +37,7 @@
 - `--include-sdk` Flag to parse SDK Library files imported.
 - `--parse-sdk` Parses the SDK libraries only. (Ignores the path passed in.)
 - `--package-root` Sets the package root of the library being analyzed.
+- `--append` Appends to the docs folder, library_list.txt, and index.txt.
 
 ###### Output Directory
 Documented libraries will be located at bin/docs in either YAML or JSON format 
@@ -47,8 +48,6 @@
 dartdoc-viewer, please take a look at the 
 [dartdoc-viewer documentation][dartdoc-viewer].
 
-[dartdoc-viewer]: https://github.com/dart-lang/dartdoc-viewer "Dartdoc-Viewer"
-
 #### Uploading to Cloud Storage
 
 To push new files to Google Cloud Storage for use by the viewer, use the 
@@ -63,3 +62,53 @@
 layout. Follow this convention and update a new VERSION file when uploading 
 a new version of documentation. You can see the format of the VERSION file 
 by running `python gsutil cat gs://dartlang-docgen/VERSION`.
+
+### Viewing Generated Documentation
+
+Docgen's generated YAML files can be used by the 
+[Dart Documentation Viewer][dartdoc-viewer] for easy viewing and navigation 
+through a project. 
+
+---
+
+#### Using dartdoc.py
+
+The `dartdoc.py` script located in the `bin` directory is a useful tool for 
+creating documentation for a Dart project and running it locally. 
+
+##### Setup
+
+The `dartdoc.py` script makes use of the 
+[Google App Engine SDK for Python][GAE]'s development server to serve the 
+documentation viewer. Install a recent version of the SDK before running 
+`dartdoc.py`.
+
+##### Running dartdoc.py
+
+######Common Options
+
+The following options are the most used:
+
+    python dartdoc.py --gae-sdk=<path to SDK>
+      --options=<path to files>
+      --options=--parse-sdk
+      --options='--include-sdk <path to files>'
+      --options='--append <path to files>'
+
+######All Options
+
+Run `python dartdoc.py -h` from the `bin` directory for all available options. 
+The two required options are as follows:
+ 
+ 1. The `--options` option describes any options being passed into `docgen.dart`.
+ If more then one option is desired, separate the options with a space 
+ (ex. `--options='--include-sdk files'`).
+ 2. The `--gae-sdk` option gives the absolute path to the 
+ [Google App Engine SDK][GAE]. 
+
+Running `python dartdoc.py --options=<docgen options> --gae-sdk=<path to SDK>` 
+will serve files generated by `docgen.dart` in your browser.
+
+[dartdoc-viewer]: https://github.com/dart-lang/dartdoc-viewer "Dartdoc-Viewer"
+[GAE]: https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Python  "Google App Engine SDK for Python"
+
diff --git a/pkg/docgen/bin/dartdoc.py b/pkg/docgen/bin/dartdoc.py
new file mode 100644
index 0000000..948a24a
--- /dev/null
+++ b/pkg/docgen/bin/dartdoc.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file. 
+
+""" Run this script to generate documentation for a directory and serve
+  the results to localhost for viewing in the browser.
+"""
+
+import argparse
+import os
+from os.path import join, dirname, abspath, exists
+import platform
+import subprocess
+import sys
+sys.path.append(abspath(join(dirname(__file__), '../../../tools')))
+import utils
+from upload_sdk import ExecuteCommand
+
+DIRECTORY = abspath(dirname(__file__))
+DART = join(DIRECTORY, '../../../%s/%s/dart-sdk/bin/dart'
+    % (utils.BUILD_ROOT[utils.GuessOS()], utils.GetBuildConf('release',
+    utils.GuessArchitecture())))
+PUB = join(DIRECTORY, '../../../sdk/bin/pub')
+DART2JS = join(DIRECTORY, '../../../sdk/bin/dart2js')
+PACKAGE_ROOT = join(DART[:-(len('dart'))], '../../packages/')
+
+def SetPackageRoot(path):
+  global PACKAGE_ROOT
+  if exists(path):
+    PACKAGE_ROOT = abspath(path)
+
+def GetOptions():
+  parser = argparse.ArgumentParser(description='Runs docgen on the specified '
+    'library and displays the resulting documentation in the browser')
+  parser.add_argument('--package-root', dest='pkg_root',
+    help='The package root for dart (default is in the build directory).',
+    action='store', default=PACKAGE_ROOT)
+  docgen = [DART, '--checked', '--package-root=' + PACKAGE_ROOT,
+    join(DIRECTORY, 'docgen.dart'), '-h']
+  process = subprocess.Popen(docgen, stdout=subprocess.PIPE)
+  out, error = process.communicate()
+  parser.add_argument('--options', help=out)
+  parser.add_argument('--gae-sdk',
+    help='The path to the Google App Engine SDK.')
+  options = parser.parse_args()
+  SetPackageRoot(options.pkg_root)
+  return options
+
+def main():
+  options = GetOptions()
+  docgen = [DART, '--checked', '--package-root=' + PACKAGE_ROOT,
+    join(DIRECTORY, 'docgen.dart')]
+  docgen.extend(options.options.split())
+  ExecuteCommand(docgen)
+  ExecuteCommand(['git', 'clone', '-b', 'dev',
+   'git://github.com/dart-lang/dartdoc-viewer.git'])
+  ExecuteCommand(['mv', 'docs', 'dartdoc-viewer/client/local'])
+  os.chdir('dartdoc-viewer/client/')
+  subprocess.call([PUB, 'install'])
+  subprocess.call([DART, 'build.dart'])
+  subprocess.call([DART2JS, '-o', 'web/out/index.html_bootstrap.dart.js', 
+    './web/out/index.html_bootstrap.dart'])
+  server = subprocess.Popen(['python', 
+    join(abspath(join(dirname(__file__), options.gae_sdk)), 'dev_appserver.py'),
+    '..'])
+  print("\nPoint your browser to the address of the 'default' server below.")
+  raw_input("Press <RETURN> to terminate the server.\n\n")
+  server.terminate()
+  os.chdir('../..')
+  subprocess.call(['rm', '-rf', 'dartdoc-viewer'])
+
+if __name__ == '__main__':
+  main()
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index b960db7..b67a321 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -37,6 +37,11 @@
 
 const String USAGE = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]';
 
+
+List<String> validAnnotations = const ['metadata.Experimental', 
+    'metadata.DomName', 'metadata.Deprecated', 'metadata.Unstable', 
+    'meta.deprecated', 'metadata.SupportedBrowser'];
+
 /// Current library being documented to be used for comment links.
 LibraryMirror _currentLibrary;
 
@@ -113,8 +118,10 @@
   var type = FileSystemEntity.typeSync(args[0]);
 
   if (type == FileSystemEntityType.FILE) {
-    libraries.add(path.absolute(args[0]));
-    logger.info('Added to libraries: ${libraries.last}');
+    if (args[0].endsWith('.dart')) {
+      libraries.add(path.absolute(args[0]));
+      logger.info('Added to libraries: ${libraries.last}');
+    }
   } else {
     libraries.addAll(_listDartFromDir(args[0]));
   }
@@ -122,14 +129,25 @@
 }
 
 List<String> _listDartFromDir(String args) {
-  var files = listDir(args, recursive: true);
+  var libraries = [];
   // To avoid anaylzing package files twice, only files with paths not
   // containing '/packages' will be added. The only exception is if the file to
   // analyze already has a '/package' in its path.
-  return files.where((f) => f.endsWith('.dart') &&
+  var files = listDir(args, recursive: true).where((f) => f.endsWith('.dart') &&
       (!f.contains('${path.separator}packages') ||
-          args.contains('${path.separator}packages'))).toList()
-      ..forEach((lib) => logger.info('Added to libraries: $lib'));
+          args.contains('${path.separator}packages'))).toList();
+  
+  files.forEach((f) {
+    // Only add the file if it does not contain 'part of' 
+    // TODO(janicejl): Remove when Issue(12406) is resolved.
+    var contents = new File(f).readAsStringSync();
+    if (!(contents.contains(new RegExp('\npart of ')) || 
+        contents.startsWith(new RegExp('part of ')))) {
+      libraries.add(f);
+      logger.info('Added to libraries: $f');
+    }
+  });
+  return libraries;
 }
 
 String _findPackageRoot(String directory) {
@@ -224,15 +242,16 @@
   filteredEntities.where((e) => e is Class || e is Library).forEach((output) {
     _writeIndexableToFile(output, outputToYaml);
   });
-  // Outputs a text file with a list of libraries available after creating all
-  // the libraries. This will help the viewer know what libraries are available
-  // to read in.
-  _writeToFile(filteredEntities.where((e) => e is Library)
-      .map((e) => e.qualifiedName).join('\n'), 'library_list.txt',
-      append: append);
-  // Outputs all the qualified names documented. This will help generate search
-  // results.
-  _writeToFile(filteredEntities.map((e) => e.qualifiedName).join('\n'),
+  // Outputs a yaml file with all libraries and their preview comments after 
+  // creating all libraries. This will help the viewer know what libraries are 
+  // available to read in.
+  var libraryMap = {'libraries' : filteredEntities.where((e) => 
+      e is Library).map((e) => e.previewMap).toList()};
+  _writeToFile(getYamlString(libraryMap), 'library_list.yaml', append: append);
+  // Outputs all the qualified names documented with their type.
+  // This will help generate search results.
+  _writeToFile(filteredEntities.map((e) => 
+      '${e.qualifiedName} ${e.typeName}').join('\n'),
       'index.txt', append: append);
 }
 
@@ -263,7 +282,11 @@
  */
 // This is because LibraryMirror.isPrivate returns `false` all the time.
 bool _isLibraryPrivate(LibraryMirror mirror) {
-  if (mirror.simpleName.startsWith('_') || mirror.simpleName.contains('._')) {
+  var sdkLibrary = LIBRARIES[mirror.simpleName];
+  if (sdkLibrary != null) {
+    return !sdkLibrary.documented;
+  } else if (mirror.simpleName.startsWith('_') || 
+      mirror.simpleName.contains('._')) {
     return true;
   }
   return false;
@@ -300,8 +323,10 @@
       .map((e) => annotation.getField(e.simpleName).reflectee)
       .where((e) => e != null)
       .toList();
-    annotations.add(new Annotation(annotation.type.qualifiedName,
-        parameterList));
+    if (validAnnotations.contains(annotation.type.qualifiedName)) {
+      annotations.add(new Annotation(annotation.type.qualifiedName,
+          parameterList));
+    }
   });
   return annotations;
 }
@@ -518,6 +543,21 @@
 
   Indexable(this.name, this.comment, this.qualifiedName, this.isPrivate,
       this.owner);
+  
+  /// The type of this member to be used in index.txt.
+  String get typeName => '';
+  
+  /**
+   * Creates a [Map] with this [Indexable]'s name and a preview comment.
+   */
+  Map get previewMap {
+    var finalMap = { 'name' : qualifiedName };
+    if (comment != '') {
+      var index = comment.indexOf('</p>');
+      finalMap['preview'] = '${comment.substring(0, index)}</p>';
+    }
+    return finalMap;
+  }
 }
 
 /**
@@ -547,6 +587,8 @@
     'functions': functions.toMap(),
     'classes': classes.toMap()
   };
+  
+  String get typeName => 'library';
 }
 
 /**
@@ -586,6 +628,8 @@
       String qualifiedName, bool isPrivate, String owner, this.isAbstract) 
       : super(name, comment, qualifiedName, isPrivate, owner);
 
+  String get typeName => 'class';
+  
   /**
    * Returns a list of all the parent classes.
    */
@@ -708,20 +752,7 @@
 
   void addClass(ClassMirror mirror) {
     _currentClass = mirror;
-    var clazz = _class(mirror);
-
-    // Adding inherited parent variables and methods.
-    clazz.parent().forEach((parent) {
-      if (_isVisible(clazz)) {
-        parent.addSubclass(clazz);
-      }
-    });
-
-    clazz.ensureComments();
-
-    if (clazz.isError()) {
-      errors[mirror.simpleName] = clazz;
-    } else if (mirror.isTypedef) {
+    if (mirror.isTypedef) {
       if (_includePrivate || !mirror.isPrivate) {
         entityMap[mirror.qualifiedName] = new Typedef(mirror.simpleName,
             mirror.value.returnType.qualifiedName, _commentToHtml(mirror),
@@ -730,10 +761,25 @@
             mirror.owner.qualifiedName);
         typedefs[mirror.simpleName] = entityMap[mirror.qualifiedName];
       }
-    } else if (mirror.isClass) {
-      classes[mirror.simpleName] = clazz;
     } else {
-      throw new ArgumentError('${mirror.simpleName} - no class type match. ');
+      var clazz = _class(mirror);
+  
+      // Adding inherited parent variables and methods.
+      clazz.parent().forEach((parent) {
+        if (_isVisible(clazz)) {
+          parent.addSubclass(clazz);
+        }
+      });
+  
+      clazz.ensureComments();
+  
+      if (clazz.isError()) {
+        errors[mirror.simpleName] = clazz;
+      } else if (mirror.isClass) {
+        classes[mirror.simpleName] = clazz;
+      } else {
+        throw new ArgumentError('${mirror.simpleName} - no class type match. ');
+      }
     }
   }
 
@@ -743,25 +789,13 @@
   bool containsKey(String name) {
     return classes.containsKey(name) || errors.containsKey(name);
   }
-
-  /**
-   * Creates a [Map] with [Class] names and a preview comment.
-   */
-  Map classMap(Class clazz) {
-    var finalMap = { 'name' : clazz.qualifiedName };
-    if (clazz.comment != '') {
-      var index = clazz.comment.indexOf('</p>');
-      finalMap['preview'] = '${clazz.comment.substring(0, index)}</p>';
-    }
-    return finalMap;
-  }
   
   Map toMap() => {
     'class': classes.values.where(_isVisible)
-      .map((e) => classMap(e)).toList(),
+      .map((e) => e.previewMap).toList(),
     'typedef': recurseMap(typedefs),
     'error': errors.values.where(_isVisible)
-      .map((e) => classMap(e)).toList()
+      .map((e) => e.previewMap).toList()
   };
 }
 
@@ -790,6 +824,8 @@
     'annotations': annotations.map((a) => a.toMap()).toList(),
     'generics': recurseMap(generics)
   };
+  
+  String get typeName => 'typedef';
 }
 
 /**
@@ -820,6 +856,8 @@
     'type': new List.filled(1, type.toMap()),
     'annotations': annotations.map((a) => a.toMap()).toList()
   };
+  
+  String get typeName => 'property';
 }
 
 /**
@@ -833,6 +871,10 @@
   bool isStatic;
   bool isAbstract;
   bool isConst;
+  bool isConstructor;
+  bool isGetter;
+  bool isSetter;
+  bool isOperator;
   Type returnType;
 
   /// Qualified name to state where the comment is inherited from.
@@ -843,8 +885,9 @@
 
   Method(String name, this.isStatic, this.isAbstract, this.isConst,
       this.returnType, String comment, this.parameters, this.annotations,
-      String qualifiedName, bool isPrivate, String owner) : super(name, comment,
-          qualifiedName, isPrivate, owner);
+      String qualifiedName, bool isPrivate, String owner, this.isConstructor,
+      this.isGetter, this.isSetter, this.isOperator) 
+        : super(name, comment, qualifiedName, isPrivate, owner);
 
   /**
    * Makes sure that the method with an inherited equivalent have comments.
@@ -870,6 +913,10 @@
     'parameters': recurseMap(parameters),
     'annotations': annotations.map((a) => a.toMap()).toList()
   };
+  
+  String get typeName => isConstructor ? 'constructor' :
+    isGetter ? 'getter' : isSetter ? 'setter' :
+    isOperator ? 'operator' : 'method';
 }
 
 /**
@@ -888,7 +935,8 @@
         mirror.isAbstract, mirror.isConstConstructor, _type(mirror.returnType),
         _commentToHtml(mirror), _parameters(mirror.parameters),
         _annotations(mirror), mirror.qualifiedName, _isHidden(mirror),
-        mirror.owner.qualifiedName);
+        mirror.owner.qualifiedName, mirror.isConstructor, mirror.isGetter,
+        mirror.isSetter, mirror.isOperator);
     entityMap[mirror.qualifiedName] = method;
     _currentMember = mirror;
     if (mirror.isSetter) {
diff --git a/pkg/fixnum/README.md b/pkg/fixnum/README.md
new file mode 100644
index 0000000..81f6467
--- /dev/null
+++ b/pkg/fixnum/README.md
@@ -0,0 +1,22 @@
+fixnum
+======
+
+A fixed-size integer library for Dart.
+- - -
+The fixnum package provides data types for signed 32- and 64-bit integers.
+The integer implementations in this library are designed to work identically
+whether executed on the Dart VM or compiled to JavaScript.
+
+Installing
+----------
+
+Use [pub](http://pub.dartlang.org) to install this package. Add the following
+to your `pubspec.yaml` file:
+
+    dependencies:
+      fixnum: any
+
+Then run `pub install`.
+
+For more information, see the
+[fixnum package on pub.dartlang.org](http://pub.dartlang.org/packages/fixnum).
diff --git a/pkg/fixnum/lib/fixnum.dart b/pkg/fixnum/lib/fixnum.dart
index 4ac6f2a..1f89dd4 100644
--- a/pkg/fixnum/lib/fixnum.dart
+++ b/pkg/fixnum/lib/fixnum.dart
@@ -2,6 +2,16 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/**
+ * Signed 32- and 64-bit integer support.
+ *
+ * The integer implementations in this library are designed to work
+ * identically whether executed on the Dart VM or compiled to JavaScript.
+ *
+ * For information on getting this library, see the
+ * [fixnum package on pub.dartlang.org]
+ * (http://pub.dartlang.org/packages/fixnum).
+ */
 library fixnum;
 
 part 'src/intx.dart';
diff --git a/pkg/fixnum/lib/src/intx.dart b/pkg/fixnum/lib/src/intx.dart
index a2bb0f0..a0cd102 100644
--- a/pkg/fixnum/lib/src/intx.dart
+++ b/pkg/fixnum/lib/src/intx.dart
@@ -9,97 +9,179 @@
  */
 abstract class IntX implements Comparable {
 
-  // Arithmetic operations.
+  /** Addition operator. */
   IntX operator +(other);
+
+  /** Subtraction operator. */
   IntX operator -(other);
-  // The unary '-' operator.  Note that -MIN_VALUE will be equal
-  // to MIN_VALUE due to overflow.
+
+  /**
+   * Negate operator.
+   *
+   * Note that `-MIN_VALUE` is equal to `MIN_VALUE` due to overflow.
+   */
   IntX operator -();
+
+  /** Multiplication operator. */
   IntX operator *(other);
+
+  /**
+   * Euclidean modulo operator.
+   *
+   * Returns the remainder of the euclidean division. The euclidean division
+   * of two integers `a` and `b` yields two integers `q` and `r` such that
+   * `a == b * q + r` and `0 <= r < a.abs()`.
+   */
   IntX operator %(other);
-  // Truncating division.
+
+  /** Truncating division operator. */
   IntX operator ~/(other);
+
+  /**
+   * Returns the remainder of the truncating division of this integer by
+   * [other].
+   */
   IntX remainder(other);
 
-  // Note: no / operator
-
-  // Bit-operations.
+  /** Bitwise and operator. */
   IntX operator &(other);
+
+  /** Bitwise or operator. */
   IntX operator |(other);
+
+  /** Bitwise xor operator. */
   IntX operator ^(other);
+
+  /** Bitwise negate operator. */
   IntX operator ~();
+
+  /**
+   * Left bit-shift operator.
+   *
+   * Returns the result of shifting the bits of this integer by [shiftAmount]
+   * bits to the left. Low-order bits are filled with zeros.
+   */
   IntX operator <<(int shiftAmount);
+
+  /**
+   * Right bit-shift operator.
+   *
+   * Returns the result of shifting the bits of this integer by [shiftAmount]
+   * bits to the right. High-order bits are filled with zero in the case where
+   * this integer is positive, or one in the case where it is negative.
+   */
   IntX operator >>(int shiftAmount);
+
+  /**
+   * Unsigned right-shift operator.
+   *
+   * Returns the result of shifting the bits of this integer by [shiftAmount]
+   * bits to the right. High-order bits are filled with zeros.
+   */
   IntX shiftRightUnsigned(int shiftAmount);
 
-  // Relational operations, may be applied to IntX or int.
   int compareTo(Comparable other);
+
+  /**
+   * Returns `true` if and only if [other] is an int or IntX equal in
+   * value to this integer.
+   */
   bool operator ==(other);
+
+  /** Relational less than operator. */
   bool operator <(other);
+
+  /** Relational less than or equal to operator. */
   bool operator <=(other);
+
+  /** Relational greater than operator. */
   bool operator >(other);
+
+  /** Relational greater than or equal to operator. */
   bool operator >=(other);
 
-  // Testers.
+  /** Returns `true` if and only if this integer is even. */
   bool get isEven;
+
+  /**
+   * Returns `true` if and only if this integer is the maximum signed value
+   * that can be represented within its bit size.
+   */
   bool get isMaxValue;
+
+  /**
+   * Returns `true` if and only if this integer is the minimum signed value
+   * that can be represented within its bit size.
+   */
   bool get isMinValue;
+
+  /** Returns `true` if and only if this integer is less than zero. */
   bool get isNegative;
+
+  /** Returns `true` if and only if this integer is odd. */
   bool get isOdd;
+
+  /** Returns `true` if and only if this integer is zero. */
   bool get isZero;
 
   int get hashCode;
 
+  /** Returns the absolute value of this integer. */
   IntX abs();
 
   /**
-   * Returns the number of leading zeros in this [IntX] as an [int]
-   * between 0 and 64.
+   * Returns the number of high-order zeros in this integer's bit
+   * representation.
    */
   int numberOfLeadingZeros();
 
   /**
-   * Returns the number of trailing zeros in this [IntX] as an [int]
-   * between 0 and 64.
+   * Returns the number of low-order zeros in this integer's bit representation.
    */
   int numberOfTrailingZeros();
 
   /**
-   * Converts this [IntX] to a [List] of [int], starting with the least
-   * significant byte.
+   * Returns a byte-sequence representation of this integer.
+   *
+   * Returns a list of int, starting with the least significant byte.
    */
   List<int> toBytes();
 
   /**
-   * Converts this [IntX] to an [int].  On some platforms, inputs with large
-   * absolute values (i.e., > 2^52) may lose some of their low bits.
+   * Returns the int representation of this integer.
+   *
+   * On some platforms, inputs with large absolute values (i.e., > 2^52) may
+   * lose some of their low-order bits.
    */
   int toInt();
 
   /**
-   * Converts an [IntX] to 32 bits.  Narrower values are sign extended and
-   * wider values have their high bits truncated.
+   * Returns an Int32 representation of this integer.
+   *
+   * Narrower values are sign-extended and wider values have their high bits
+   * truncated.
    */
   Int32 toInt32();
 
-  /**
-   * Converts an [IntX] to 64 bits.
-   */
+  /** Returns an Int64 representation of this integer. */
   Int64 toInt64();
 
   /**
-   * Returns the value of this [IntX] as a decimal [String].
+   * Returns a string representing the value of this integer in decimal
+   * notation; example: `'13'`.
    */
   String toString();
 
   /**
-   * Returns the value of this [IntX] as a hexadecimal [String].
+   * Returns a string representing the value of this integer in hexadecimal
+   * notation; example: `'0xd'`.
    */
   String toHexString();
 
   /**
-   * Returns the value of this [IntX] as a [String] in the given radix.
-   * [radix] must be an integer between 2 and 16, inclusive.
+   * Returns a string representing the value of this integer in the given radix.
+   *
+   * [radix] must be an integer in the range 2 .. 16, inclusive.
    */
   String toRadixString(int radix);
 }
diff --git a/pkg/intl/lib/src/http_request_data_reader.dart b/pkg/intl/lib/src/http_request_data_reader.dart
index 530dce6..bd86d66 100644
--- a/pkg/intl/lib/src/http_request_data_reader.dart
+++ b/pkg/intl/lib/src/http_request_data_reader.dart
@@ -19,5 +19,10 @@
   String url;
   HTTPRequestDataReader(this.url);
 
-  Future read(String locale) => HttpRequest.getString('$url$locale.json');
+  Future read(String locale) {
+    // TODO(alanknight): Remove this once it's not necessary for Chrome.
+    // Without it, the tests will be flaky on Chrome. Issue 11834.
+    var someNumber = new DateTime.now().millisecondsSinceEpoch;
+    return HttpRequest.getString('$url$locale.json?cacheBlocker=$someNumber');
+  }
 }
diff --git a/pkg/intl/lib/src/intl_message.dart b/pkg/intl/lib/src/intl_message.dart
index 5dfb9c8..886c82d 100644
--- a/pkg/intl/lib/src/intl_message.dart
+++ b/pkg/intl/lib/src/intl_message.dart
@@ -77,18 +77,17 @@
     if (messageName == null) {
       return "The 'name' argument for Intl.message must be specified";
     }
-    if ((messageName.expression is! SimpleStringLiteral)
-        || messageName.expression.value != outerName) {
+    if (messageName.expression is! SimpleStringLiteral) {
       return "The 'name' argument for Intl.message must be a simple string "
-          "literal and match the containing function name.";
+          "literal.";
     }
     var simpleArguments = arguments.where(
         (each) => each is NamedExpression
-        && ["desc", "locale", "name"].contains(each.name.label.name));
+        && ["desc", "name"].contains(each.name.label.name));
     var values = simpleArguments.map((each) => each.expression).toList();
     for (var arg in values) {
       if (arg is! SimpleStringLiteral) {
-        return "Intl.message argument '${arg.name.label.name}' must be "
+        return "Intl.message argument '$arg' must be "
             "a simple string literal";
       }
     }
@@ -213,7 +212,7 @@
 class CompositeMessage extends Message {
   List<Message> pieces;
 
-  CompositeMessage.parent(parent) : super(parent);
+  CompositeMessage.withParent(parent) : super(parent);
   CompositeMessage(this.pieces, ComplexMessage parent) : super(parent) {
     pieces.forEach((x) => x.parent = this);
   }
@@ -641,4 +640,4 @@
     out.write("})}");
     return out.toString();
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/make_hardcoded_translation.dart b/pkg/intl/test/message_extraction/make_hardcoded_translation.dart
index dd907de..9da9dce 100644
--- a/pkg/intl/test/message_extraction/make_hardcoded_translation.dart
+++ b/pkg/intl/test/message_extraction/make_hardcoded_translation.dart
@@ -27,7 +27,7 @@
       constructorFields: ["index", "parent"])
   ..addRuleFor(new LiteralString("a", null),
       constructorFields: ["string", "parent"])
-  ..addRuleFor(new CompositeMessage([], null), constructor: "parent",
+  ..addRuleFor(new CompositeMessage([], null), constructor: "withParent",
       constructorFields: ["parent"]);
 var format = const SimpleFlatFormat();
 get writer => serialization.newWriter(format);
@@ -240,4 +240,4 @@
   var messages = json.parse(new File(fileArgs.first).readAsStringSync());
   translate(messages, "fr", french);
   translate(messages, "de_DE", german);
-}
\ No newline at end of file
+}
diff --git a/pkg/pkg.gyp b/pkg/pkg.gyp
index 3da13fc..f74e040 100644
--- a/pkg/pkg.gyp
+++ b/pkg/pkg.gyp
@@ -14,6 +14,8 @@
             '../tools/make_links.py',
             '<!@(["python", "../tools/list_pkg_directories.py", "."])',
             '<!@(["python", "../tools/list_pkg_directories.py", '
+                '"third_party"])',
+            '<!@(["python", "../tools/list_pkg_directories.py", '
                 '"../third_party/pkg"])',
           ],
           'outputs': [
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 03873c1..81660c1 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -15,6 +15,12 @@
 scheduled_test/test/scheduled_server_test: Pass, Fail, Slow, Crash # Issue 9231, 9582
 scheduled_test/test/scheduled_process_test: Pass, Slow # Issue 9231
 
+# Skip test not runnable via test.dart
+third_party/html5lib/test/dom_compat_test: Skip
+
+[ $compiler == dart2js && $runtime == d8 ]
+unmodifiable_collection/test/unmodifiable_collection_test: Pass, Fail # Issue 12429
+
 [ $compiler == dart2js ]
 analyzer_experimental/test/generated/ast_test: Fail #Issue 12341
 
@@ -45,13 +51,11 @@
 intl/test/date_time_format_http_request_test: Fail # Issue 8983
 mime/test/mime_multipart_transformer_test: Skip # No typed_data on IE9.
 
-[ $runtime == chrome && $compiler == dart2js ]
-intl/test/date_time_format_http_request_test: Pass, Fail # Issue: 12239
-
 [ $runtime == safari ]
 fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
 crypto/test/hmac_sha1_test: Fail # Issue 11407.
 crypto/test/sha1_test: Fail # Issue 11407.
+stack_trace/test/trace_test: Fail # http://dartbug.com/12380
 
 # Skip browser-specific tests on VM
 [ $runtime == vm ]
@@ -89,12 +93,20 @@
 # printed. Minified versions of these tests exist that test the behavior when
 # minified.
 unittest/test/*_unminified_test: Skip # DO NOT COPY THIS UNLESS YOU WORK ON DART2JS
+csslib: Pass, Crash # crashing randomly, see issue 12468
 
 [ $compiler == dart2js && $browser ]
 stack_trace/test/vm_test: Fail, OK # VM-specific traces
 crypto/test/sha256_test: Slow, Pass
 crypto/test/sha1_test: Slow, Pass
 
+[ $compiler == dart2js ]
+csslib/test/var_test: Fail # looking for VM-specific stack traces, issue 12469
+
+[ $compiler == dart2js && $runtime == drt ]
+third_party/html5lib/test/parser_feature_test: Fail # issue 12466
+csslib: Pass, Fail # issue 12466
+
 [ $browser ]
 analyzer_experimental/test/error_test: Fail, OK # Uses dart:io.
 analyzer_experimental/test/generated/element_test: Fail, OK # Uses dart:io.
@@ -148,6 +160,10 @@
 
 */test/analyzer_test: Skip  # No need to run analysis tests on browser bots
 
+# Skip tests on the browser if the test depends on dart:io
+third_party/html5lib/test/parser_test: Skip
+third_party/html5lib/test/tokenizer_test: Skip
+
 [ $runtime == safari]
  # Bug in JSC: the test only passes when being debugged.
 crypto/test/hmac_md5_test: Fail, Pass
@@ -183,6 +199,7 @@
 custom_element: Skip
 mdv: Skip
 mutation_observer: Skip
+third_party/html5lib/test/browser/browser_test: Skip
 
 [ $runtime == safari || $runtime == chrome || $runtime == ie9 || $runtime == ff || $runtime == dartium || $runtime == drt ]
 docgen/test/single_library_test: Skip # Uses dart:io
diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart
index 2205181b..9323ec1 100644
--- a/pkg/serialization/lib/serialization.dart
+++ b/pkg/serialization/lib/serialization.dart
@@ -220,12 +220,13 @@
  * See library comment for examples of usage.
  */
 class Serialization {
+  final List<SerializationRule> _rules;
 
   /**
    * The serialization is controlled by the list of Serialization rules. These
    * are most commonly added via [addRuleFor].
    */
-  final List<SerializationRule> rules = new List<SerializationRule>();
+  final UnmodifiableListView<SerializationRule> rules;
 
   /**
    * When reading, we may need to resolve references to existing objects in
@@ -279,16 +280,21 @@
    * Creates a new serialization with a default set of rules for primitives
    * and lists.
    */
-  Serialization() {
-    addDefaultRules();
-  }
+  factory Serialization() =>
+    new Serialization.blank()
+      ..addDefaultRules();
 
   /**
    * Creates a new serialization with no default rules at all. The most common
    * use for this is if we are reading self-describing serialized data and
    * will populate the rules from that data.
    */
-  Serialization.blank() { }
+  factory Serialization.blank()
+    => new Serialization._(new List<SerializationRule>());
+
+  Serialization._(List<SerializationRule> rules) :
+    this._rules = rules,
+    this.rules = new UnmodifiableListView(rules);
 
   /**
    * Create a [BasicRule] rule for the type of
@@ -350,8 +356,8 @@
    * method.
    */
   void addRule(SerializationRule rule) {
-    rule.number = rules.length;
-    rules.add(rule);
+    rule.number = _rules.length;
+    _rules.add(rule);
   }
 
   /**
diff --git a/pkg/serialization/lib/src/basic_rule.dart b/pkg/serialization/lib/src/basic_rule.dart
index 927f316..005580a 100644
--- a/pkg/serialization/lib/src/basic_rule.dart
+++ b/pkg/serialization/lib/src/basic_rule.dart
@@ -25,10 +25,10 @@
   final ClassMirror type;
 
   /** Used to create new objects when reading. */
-  Constructor constructor;
+  final Constructor constructor;
 
   /** This holds onto our list of fields, and can also calculate them. */
-  _FieldList _fields;
+  final _FieldList _fields;
 
   /**
    * Instances can either use maps or lists to hold the object's state. The list
@@ -58,12 +58,23 @@
    * [excludeFields] lets you tell it to find the fields automatically, but
    *   omit some that would otherwise be included.
    */
-  BasicRule(ClassMirror this.type, String constructorName,
-      List constructorFields, List regularFields,
-      List excludeFields) {
-    _findFields(constructorFields, regularFields, excludeFields);
-    constructor = new Constructor(
-        type, constructorName, _fields.constructorFieldIndices());
+  factory BasicRule(ClassMirror type, String constructorName,
+      List constructorFields, List regularFields, List excludeFields) {
+
+    var fields = new _FieldList(type);
+    fields.constructorFields = constructorFields;
+    fields.regular = regularFields;
+    // TODO(alanknight): The order of this matters. It shouldn't.
+    fields.exclude = excludeFields;
+    fields.figureOutFields();
+
+    var constructor = new Constructor(type, constructorName,
+        fields.constructorFieldIndices());
+
+    return new BasicRule._(type, constructor, fields);
+  }
+
+  BasicRule._(this.type, this.constructor, this._fields) {
     configureForLists();
   }
 
@@ -243,20 +254,6 @@
   // TODO(alanknight): This seems likely to be slow. Verify. Other options?
   bool appliesTo(object, Writer w) => reflect(object).type == type;
 
-  /**
-   * Given the various field lists provided by the user, construct the list
-   * of field names that we want.
-   */
-  void _findFields(List constructorFields, List regularFields,
-      List excludeFields) {
-    _fields = new _FieldList(type);
-    _fields.constructorFields = constructorFields;
-    _fields.regular = regularFields;
-    // TODO(alanknight): The order of this matters. It shouldn't.
-    _fields.exclude = excludeFields;
-    _fields.figureOutFields();
-  }
-
   bool get hasVariableLengthEntries => false;
 
   int get dataLength => _fields.length;
diff --git a/pkg/serialization/lib/src/serialization_rule.dart b/pkg/serialization/lib/src/serialization_rule.dart
index ddfac08..12c7eb7 100644
--- a/pkg/serialization/lib/src/serialization_rule.dart
+++ b/pkg/serialization/lib/src/serialization_rule.dart
@@ -107,7 +107,7 @@
    * variables from the representation in [state]. Where there are references
    * to other objects they are resolved in the context of [reader].
    */
-  inflateNonEssential(state, object, Reader reader);
+  void inflateNonEssential(state, object, Reader reader);
 
   /**
    * If we have [object] as part of our state, should we represent that
@@ -155,7 +155,7 @@
 
   // For a list, we consider all of its state non-essential and add it
   // after creation.
-  inflateNonEssential(List state, List newList, Reader r) {
+  void inflateNonEssential(List state, List newList, Reader r) {
     populateContents(state, newList, r);
   }
 
@@ -183,7 +183,7 @@
   }
 
   /** Does nothing, because all the work has been done in inflateEssential. */
-  inflateNonEssential(state, newList, reader) {}
+  void inflateNonEssential(state, newList, reader) {}
 
   bool get mustBePrimary => true;
 }
@@ -237,7 +237,7 @@
 
   // For a map, we consider all of its state non-essential and add it
   // after creation.
-  inflateNonEssential(state, Map newMap, Reader r) {
+  void inflateNonEssential(state, Map newMap, Reader r) {
     if (state is List) {
       inflateNonEssentialFromList(state, newMap, r);
     } else {
@@ -276,7 +276,7 @@
   extractState(object, Function f, Writer w) => object;
   flatten(object, Writer writer) {}
   inflateEssential(state, Reader r) => state;
-  inflateNonEssential(object, _, Reader r) {}
+  void inflateNonEssential(object, _, Reader r) {}
 
   bool get storesStateAsPrimitives => true;
 
@@ -310,13 +310,13 @@
   final Type type;
 
   /** The function for constructing new objects when reading. */
-  ConstructType construct;
+  final ConstructType construct;
 
   /** The function for returning an object's state as a Map. */
-  GetStateType getStateFunction;
+  final GetStateType getStateFunction;
 
   /** The function for setting an object's state from a Map. */
-  NonEssentialStateType setNonEssentialState;
+  final NonEssentialStateType setNonEssentialState;
 
   /**
    * Create a ClosureToMapRule for the given [type] which gets an object's
@@ -374,7 +374,7 @@
       r.objectNamed(r.resolveReference(state.first));
 
   /** Set any non-essential state on the object. For this rule, a no-op. */
-  inflateNonEssential(state, object, Reader r) {}
+  void inflateNonEssential(state, object, Reader r) {}
 
   /** Return the name for this object in the Writer. */
   String nameFor(object, Writer writer) => writer.nameFor(object);
@@ -496,7 +496,7 @@
 class DateTimeRule extends CustomRule {
   bool appliesTo(instance, _) => instance is DateTime;
   List getState(DateTime date) => [date.millisecondsSinceEpoch, date.isUtc];
-  create(List state) =>
+  DateTime create(List state) =>
       new DateTime.fromMillisecondsSinceEpoch(state[0], isUtc: state[1]);
   void setState(date, state) {}
   // Let the system know we don't have to store a length for these.
@@ -558,7 +558,7 @@
  * looks like it's just a list of objects to a [CustomRule] without needing
  * to inflate all the references in advance.
  */
-class _LazyList extends IterableBase with ListMixin implements List {
+class _LazyList extends ListBase {
   _LazyList(this._raw, this._reader);
 
   final List _raw;
diff --git a/pkg/stack_trace/lib/src/frame.dart b/pkg/stack_trace/lib/src/frame.dart
index 5a0582c..3db4ab5 100644
--- a/pkg/stack_trace/lib/src/frame.dart
+++ b/pkg/stack_trace/lib/src/frame.dart
@@ -97,6 +97,12 @@
 
   /// Parses a string representation of a Dart VM stack frame.
   factory Frame.parseVM(String frame) {
+    // The VM sometimes folds multiple stack frames together and replaces them
+    // with "...".
+    if (frame == '...') {
+      return new Frame(new Uri(), null, null, '...');
+    }
+
     var match = _vmFrame.firstMatch(frame);
     if (match == null) {
       throw new FormatException("Couldn't parse VM stack trace line '$frame'.");
diff --git a/pkg/stack_trace/lib/src/trace.dart b/pkg/stack_trace/lib/src/trace.dart
index 6b7da75..863d64e 100644
--- a/pkg/stack_trace/lib/src/trace.dart
+++ b/pkg/stack_trace/lib/src/trace.dart
@@ -72,14 +72,19 @@
   /// [trace] should be formatted in the same way as a Dart VM or browser stack
   /// trace.
   factory Trace.parse(String trace) {
-    if (trace.isEmpty) return new Trace(<Frame>[]);
-    if (trace.startsWith("Error\n")) return new Trace.parseV8(trace);
-    if (trace.contains(_firefoxTrace)) return new Trace.parseFirefox(trace);
-    if (trace.contains(_friendlyTrace)) return new Trace.parseFriendly(trace);
+    try {
+      if (trace.isEmpty) return new Trace(<Frame>[]);
+      if (trace.startsWith("Error\n")) return new Trace.parseV8(trace);
+      if (trace.contains(_firefoxTrace)) return new Trace.parseFirefox(trace);
+      if (trace.contains(_friendlyTrace)) return new Trace.parseFriendly(trace);
 
-    // Default to parsing the stack trace as a VM trace. This is also hit on IE
-    // and Safari, where the stack trace is just an empty string (issue 11257).
-    return new Trace.parseVM(trace);
+      // Default to parsing the stack trace as a VM trace. This is also hit on
+      // IE and Safari, where the stack trace is just an empty string (issue
+      // 11257).
+      return new Trace.parseVM(trace);
+    } on FormatException catch (error) {
+      throw new FormatException('${error.message}\nStack trace:\n$trace');
+    }
   }
 
   /// Parses a string representation of a Dart VM stack trace.
diff --git a/pkg/stack_trace/test/frame_test.dart b/pkg/stack_trace/test/frame_test.dart
index 75302a7..0be717d 100644
--- a/pkg/stack_trace/test/frame_test.dart
+++ b/pkg/stack_trace/test/frame_test.dart
@@ -29,6 +29,15 @@
           equals('<fn>.<fn>.bar'));
     });
 
+    test('parses a folded frame correctly', () {
+      var frame = new Frame.parseVM('...');
+
+      expect(frame.member, equals('...'));
+      expect(frame.uri, equals(new Uri()));
+      expect(frame.line, isNull);
+      expect(frame.column, isNull);
+    });
+
     test('throws a FormatException for malformed frames', () {
       expect(() => new Frame.parseVM(''), throwsFormatException);
       expect(() => new Frame.parseVM('#1'), throwsFormatException);
diff --git a/pkg/third_party/html5lib/LICENSE b/pkg/third_party/html5lib/LICENSE
new file mode 100644
index 0000000..d5ee641
--- /dev/null
+++ b/pkg/third_party/html5lib/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2006-2012 The Authors
+
+Contributors:
+James Graham - jg307@cam.ac.uk
+Anne van Kesteren - annevankesteren@gmail.com
+Lachlan Hunt - lachlan.hunt@lachy.id.au
+Matt McDonald - kanashii@kanashii.ca
+Sam Ruby - rubys@intertwingly.net
+Ian Hickson (Google) - ian@hixie.ch
+Thomas Broyer - t.broyer@ltgt.net
+Jacques Distler - distler@golem.ph.utexas.edu
+Henri Sivonen - hsivonen@iki.fi
+Adam Barth - abarth@webkit.org
+Eric Seidel - eric@webkit.org
+The Mozilla Foundation (contributions from Henri Sivonen since 2008)
+David Flanagan (Mozilla) - dflanagan@mozilla.com
+Google Inc. (contributed the Dart port) - misc@dartlang.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/pkg/third_party/html5lib/README.md b/pkg/third_party/html5lib/README.md
new file mode 100644
index 0000000..4a8319c
--- /dev/null
+++ b/pkg/third_party/html5lib/README.md
@@ -0,0 +1,56 @@
+html5lib in Pure Dart
+=====================
+
+This is a pure [Dart][dart] [html5 parser][html5parse]. It's a port of
+[html5lib](http://code.google.com/p/html5lib/) from Python. Since it's 100%
+Dart you can use it safely from a script or server side app.
+
+Eventually the parse tree API will be compatible with [dart:html][d_html], so
+the same code will work on the client and the server.
+
+Installation
+------------
+
+Add this to your `pubspec.yaml` (or create it):
+```yaml
+dependencies:
+  html5lib: any
+```
+Then run the [Pub Package Manager][pub] (comes with the Dart SDK):
+
+    pub install
+
+Usage
+-----
+
+Parsing HTML is easy!
+```dart
+import 'package:html5lib/parser.dart' show parse;
+import 'package:html5lib/dom.dart';
+
+main() {
+  var document = parse(
+      '<body>Hello world! <a href="www.html5rocks.com">HTML5 rocks!');
+  print(document.outerHtml);
+}
+```
+
+You can pass a String or list of bytes to `parse`.
+There's also `parseFragment` for parsing a document fragment, and `HtmlParser`
+if you want more low level control.
+
+Running Tests
+-------------
+
+```bash
+# From Dart SVN checkout
+./tools/build.py -m release
+./tools/test.py -m release html5lib
+./tools/test.py -m release -r drt html5lib
+```
+
+[dart]: http://www.dartlang.org/
+[html5parse]: http://dev.w3.org/html5/spec/parsing.html
+[d_html]: http://api.dartlang.org/docs/continuous/dart_html.html
+[files]: http://html5lib.googlecode.com/hg/python/html5lib/
+[pub]: http://www.dartlang.org/docs/pub-package-manager/
diff --git a/pkg/third_party/html5lib/lib/dom.dart b/pkg/third_party/html5lib/lib/dom.dart
new file mode 100644
index 0000000..d73edaa
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/dom.dart
@@ -0,0 +1,871 @@
+/**
+ * A simple tree API that results from parsing html. Intended to be compatible
+ * with dart:html, but right now it resembles the classic JS DOM.
+ */
+library dom;
+
+import 'dart:collection';
+import 'package:source_maps/span.dart' show FileSpan;
+
+import 'src/constants.dart';
+import 'src/list_proxy.dart';
+import 'src/token.dart';
+import 'src/tokenizer.dart';
+import 'src/treebuilder.dart';
+import 'src/utils.dart';
+import 'dom_parsing.dart';
+import 'parser.dart';
+
+// TODO(jmesserly): this needs to be replaced by an AttributeMap for attributes
+// that exposes namespace info.
+class AttributeName implements Comparable {
+  /** The namespace prefix, e.g. `xlink`. */
+  final String prefix;
+
+  /** The attribute name, e.g. `title`. */
+  final String name;
+
+  /** The namespace url, e.g. `http://www.w3.org/1999/xlink` */
+  final String namespace;
+
+  const AttributeName(this.prefix, this.name, this.namespace);
+
+  String toString() {
+    // Implement:
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
+    // If we get here we know we are xml, xmlns, or xlink, because of
+    // [HtmlParser.adjustForeignAttriubtes] is the only place we create
+    // an AttributeName.
+    return prefix != null ? '$prefix:$name' : name;
+  }
+
+  int get hashCode {
+    int h = prefix.hashCode;
+    h = 37 * (h & 0x1FFFFF) + name.hashCode;
+    h = 37 * (h & 0x1FFFFF) + namespace.hashCode;
+    return h & 0x3FFFFFFF;
+  }
+
+  int compareTo(other) {
+    // Not sure about this sort order
+    if (other is! AttributeName) return 1;
+    int cmp = (prefix != null ? prefix : "").compareTo(
+          (other.prefix != null ? other.prefix : ""));
+    if (cmp != 0) return cmp;
+    cmp = name.compareTo(other.name);
+    if (cmp != 0) return cmp;
+    return namespace.compareTo(other.namespace);
+  }
+
+  bool operator ==(x) {
+    if (x is! AttributeName) return false;
+    return prefix == x.prefix && name == x.name && namespace == x.namespace;
+  }
+}
+
+/** Really basic implementation of a DOM-core like Node. */
+abstract class Node {
+  static const int ATTRIBUTE_NODE = 2;
+  static const int CDATA_SECTION_NODE = 4;
+  static const int COMMENT_NODE = 8;
+  static const int DOCUMENT_FRAGMENT_NODE = 11;
+  static const int DOCUMENT_NODE = 9;
+  static const int DOCUMENT_TYPE_NODE = 10;
+  static const int ELEMENT_NODE = 1;
+  static const int ENTITY_NODE = 6;
+  static const int ENTITY_REFERENCE_NODE = 5;
+  static const int NOTATION_NODE = 12;
+  static const int PROCESSING_INSTRUCTION_NODE = 7;
+  static const int TEXT_NODE = 3;
+
+  // TODO(jmesserly): this should be on Element
+  /** The tag name associated with the node. */
+  final String tagName;
+
+  /** The parent of the current node (or null for the document node). */
+  Node parent;
+
+  // TODO(jmesserly): should move to Element.
+  /**
+   * A map holding name, value pairs for attributes of the node.
+   *
+   * Note that attribute order needs to be stable for serialization, so we use a
+   * LinkedHashMap. Each key is a [String] or [AttributeName].
+   */
+  LinkedHashMap<dynamic, String> attributes = new LinkedHashMap();
+
+  /**
+   * A list of child nodes of the current node. This must
+   * include all elements but not necessarily other node types.
+   */
+  final NodeList nodes = new NodeList._();
+
+  List<Element> _elements;
+
+  // TODO(jmesserly): consider using an Expando for this, and put it in
+  // dom_parsing. Need to check the performance affect.
+  /** The source span of this node, if it was created by the [HtmlParser]. */
+  FileSpan sourceSpan;
+
+  /** The attribute spans if requested. Otherwise null. */
+  LinkedHashMap<dynamic, FileSpan> _attributeSpans;
+  LinkedHashMap<dynamic, FileSpan> _attributeValueSpans;
+
+  Node(this.tagName) {
+    nodes._parent = this;
+  }
+
+  /**
+   * If [sourceSpan] is available, this contains the spans of each attribute.
+   * The span of an attribute is the entire attribute, including the name and
+   * quotes (if any). For example, the span of "attr" in `<a attr="value">`
+   * would be the text `attr="value"`.
+   */
+  LinkedHashMap<dynamic, FileSpan> get attributeSpans {
+    _ensureAttributeSpans();
+    return _attributeSpans;
+  }
+
+  /**
+   * If [sourceSpan] is available, this contains the spans of each attribute's
+   * value. Unlike [attributeSpans], this span will inlcude only the value.
+   * For example, the value span of "attr" in `<a attr="value">` would be the
+   * text `value`.
+   */
+  LinkedHashMap<dynamic, FileSpan> get attributeValueSpans {
+    _ensureAttributeSpans();
+    return _attributeValueSpans;
+  }
+
+  List<Element> get children {
+    if (_elements == null) {
+      _elements = new FilteredElementList(this);
+    }
+    return _elements;
+  }
+
+  // TODO(jmesserly): needs to support deep clone.
+  /**
+   * Return a shallow copy of the current node i.e. a node with the same
+   * name and attributes but with no parent or child nodes.
+   */
+  Node clone();
+
+  String get namespace => null;
+
+  // TODO(jmesserly): do we need this here?
+  /** The value of the current node (applies to text nodes and comments). */
+  String get value => null;
+
+  // TODO(jmesserly): this is a workaround for http://dartbug.com/4754
+  int get $dom_nodeType => nodeType;
+
+  int get nodeType;
+
+  String get outerHtml {
+    var str = new StringBuffer();
+    _addOuterHtml(str);
+    return str.toString();
+  }
+
+  String get innerHtml {
+    var str = new StringBuffer();
+    _addInnerHtml(str);
+    return str.toString();
+  }
+
+  set innerHtml(String value) {
+    nodes.clear();
+    // TODO(jmesserly): should be able to get the same effect by adding the
+    // fragment directly.
+    nodes.addAll(parseFragment(value, container: tagName).nodes);
+  }
+
+  void _addOuterHtml(StringBuffer str);
+
+  void _addInnerHtml(StringBuffer str) {
+    for (Node child in nodes) child._addOuterHtml(str);
+  }
+
+  String toString() => tagName;
+
+  Node remove() {
+    // TODO(jmesserly): is parent == null an error?
+    if (parent != null) {
+      parent.nodes.remove(this);
+    }
+    return this;
+  }
+
+  /**
+   * Insert [node] as a child of the current node, before [refNode] in the
+   * list of child nodes. Raises [UnsupportedOperationException] if [refNode]
+   * is not a child of the current node. If refNode is null, this adds to the
+   * end of the list.
+   */
+  void insertBefore(Node node, Node refNode) {
+    if (refNode == null) {
+      nodes.add(node);
+    } else {
+      nodes.insert(nodes.indexOf(refNode), node);
+    }
+  }
+
+  /** Replaces this node with another node. */
+  Node replaceWith(Node otherNode) {
+    if (parent == null) {
+      throw new UnsupportedError('Node must have a parent to replace it.');
+    }
+    parent.nodes[parent.nodes.indexOf(this)] = otherNode;
+    return this;
+  }
+
+  // TODO(jmesserly): should this be a property or remove?
+  /** Return true if the node has children or text. */
+  bool hasContent() => nodes.length > 0;
+
+  Pair<String, String> get nameTuple {
+    var ns = namespace != null ? namespace : Namespaces.html;
+    return new Pair(ns, tagName);
+  }
+
+  /**
+   * Move all the children of the current node to [newParent].
+   * This is needed so that trees that don't store text as nodes move the
+   * text in the correct way.
+   */
+  void reparentChildren(Node newParent) {
+    newParent.nodes.addAll(nodes);
+    nodes.clear();
+  }
+
+  /**
+   * Seaches for the first descendant node matching the given selectors, using a
+   * preorder traversal. NOTE: right now, this supports only a single type
+   * selectors, e.g. `node.query('div')`.
+   */
+  Element query(String selectors) => _queryType(_typeSelector(selectors));
+
+  /**
+   * Returns all descendant nodes matching the given selectors, using a
+   * preorder traversal. NOTE: right now, this supports only a single type
+   * selectors, e.g. `node.queryAll('div')`.
+   */
+  List<Element> queryAll(String selectors) {
+    var results = new List<Element>();
+    _queryAllType(_typeSelector(selectors), results);
+    return results;
+  }
+
+  bool hasChildNodes() => !nodes.isEmpty;
+
+  bool contains(Node node) => nodes.contains(node);
+
+  String _typeSelector(String selectors) {
+    selectors = selectors.trim();
+    if (!_isTypeSelector(selectors)) {
+      throw new UnimplementedError('only type selectors are implemented');
+    }
+    return selectors;
+  }
+
+  /**
+   * Checks if this is a type selector.
+   * See <http://www.w3.org/TR/CSS2/grammar.html>.
+   * Note: this doesn't support '*', the universal selector, non-ascii chars or
+   * escape chars.
+   */
+  bool _isTypeSelector(String selector) {
+    // Parser:
+
+    // element_name
+    //   : IDENT | '*'
+    //   ;
+
+    // Lexer:
+
+    // nmstart   [_a-z]|{nonascii}|{escape}
+    // nmchar    [_a-z0-9-]|{nonascii}|{escape}
+    // ident   -?{nmstart}{nmchar}*
+    // nonascii  [\240-\377]
+    // unicode   \\{h}{1,6}(\r\n|[ \t\r\n\f])?
+    // escape    {unicode}|\\[^\r\n\f0-9a-f]
+
+    // As mentioned above, no nonascii or escape support yet.
+    int len = selector.length;
+    if (len == 0) return false;
+
+    int i = 0;
+    const int DASH = 45;
+    if (selector.codeUnitAt(i) == DASH) i++;
+
+    if (i >= len || !isLetter(selector[i])) return false;
+    i++;
+
+    for (; i < len; i++) {
+      if (!isLetterOrDigit(selector[i]) && selector.codeUnitAt(i) != DASH) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  Element _queryType(String tag) {
+    for (var node in nodes) {
+      if (node is! Element) continue;
+      if (node.tagName == tag) return node;
+      var result = node._queryType(tag);
+      if (result != null) return result;
+    }
+    return null;
+  }
+
+  void _queryAllType(String tag, List<Element> results) {
+    for (var node in nodes) {
+      if (node is! Element) continue;
+      if (node.tagName == tag) results.add(node);
+      node._queryAllType(tag, results);
+    }
+  }
+
+  /** Initialize [attributeSpans] using [sourceSpan]. */
+  void _ensureAttributeSpans() {
+    if (_attributeSpans != null) return;
+
+    _attributeSpans = new LinkedHashMap<dynamic, FileSpan>();
+    _attributeValueSpans = new LinkedHashMap<dynamic, FileSpan>();
+
+    if (sourceSpan == null) return;
+
+    var tokenizer = new HtmlTokenizer(sourceSpan.text, generateSpans: true,
+        attributeSpans: true);
+
+    tokenizer.moveNext();
+    var token = tokenizer.current as StartTagToken;
+
+    if (token.attributeSpans == null) return; // no attributes
+
+    for (var attr in token.attributeSpans) {
+      var offset = sourceSpan.start.offset;
+      _attributeSpans[attr.name] = sourceSpan.file.span(
+          offset + attr.start, offset + attr.end);
+      if (attr.startValue != null) {
+        _attributeValueSpans[attr.name] = sourceSpan.file.span(
+            offset + attr.startValue, offset + attr.endValue);
+      }
+    }
+  }
+}
+
+class Document extends Node {
+  Document() : super(null);
+  factory Document.html(String html) => parse(html);
+
+  int get nodeType => Node.DOCUMENT_NODE;
+
+  // TODO(jmesserly): optmize this if needed
+  Element get head => query('html').query('head');
+  Element get body => query('html').query('body');
+
+  String toString() => "#document";
+
+  void _addOuterHtml(StringBuffer str) => _addInnerHtml(str);
+
+  Document clone() => new Document();
+}
+
+class DocumentFragment extends Document {
+  DocumentFragment();
+  factory DocumentFragment.html(String html) => parseFragment(html);
+
+  int get nodeType => Node.DOCUMENT_FRAGMENT_NODE;
+
+  String toString() => "#document-fragment";
+
+  DocumentFragment clone() => new DocumentFragment();
+}
+
+class DocumentType extends Node {
+  final String publicId;
+  final String systemId;
+
+  DocumentType(String name, this.publicId, this.systemId) : super(name);
+
+  int get nodeType => Node.DOCUMENT_TYPE_NODE;
+
+  String toString() {
+    if (publicId != null || systemId != null) {
+      // TODO(jmesserly): the html5 serialization spec does not add these. But
+      // it seems useful, and the parser can handle it, so for now keeping it.
+      var pid = publicId != null ? publicId : '';
+      var sid = systemId != null ? systemId : '';
+      return '<!DOCTYPE $tagName "$pid" "$sid">';
+    } else {
+      return '<!DOCTYPE $tagName>';
+    }
+  }
+
+
+  void _addOuterHtml(StringBuffer str) {
+    str.write(toString());
+  }
+
+  DocumentType clone() => new DocumentType(tagName, publicId, systemId);
+}
+
+class Text extends Node {
+  // TODO(jmesserly): this should be text?
+  String value;
+
+  Text(this.value) : super(null);
+
+  int get nodeType => Node.TEXT_NODE;
+
+  String toString() => '"$value"';
+
+  void _addOuterHtml(StringBuffer str) {
+    // Don't escape text for certain elements, notably <script>.
+    if (rcdataElements.contains(parent.tagName) ||
+        parent.tagName == 'plaintext') {
+      str.write(value);
+    } else {
+      str.write(htmlSerializeEscape(value));
+    }
+  }
+
+  Text clone() => new Text(value);
+}
+
+class Element extends Node {
+  final String namespace;
+
+  // TODO(jmesserly): deprecate in favor of Element.tag? Or rename?
+  Element(String name, [this.namespace]) : super(name);
+
+  Element.tag(String name) : namespace = null, super(name);
+
+  static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
+
+  static final _CUSTOM_PARENT_TAG_MAP = const {
+    'body': 'html',
+    'head': 'html',
+    'caption': 'table',
+    'td': 'tr',
+    'colgroup': 'table',
+    'col': 'colgroup',
+    'tr': 'tbody',
+    'tbody': 'table',
+    'tfoot': 'table',
+    'thead': 'table',
+    'track': 'audio',
+  };
+
+  // TODO(jmesserly): this is from dart:html _ElementFactoryProvider...
+  // TODO(jmesserly): have a look at fixing some things in dart:html, in
+  // particular: is the parent tag map complete? Is it faster without regexp?
+  // TODO(jmesserly): for our version we can do something smarter in the parser.
+  // All we really need is to set the correct parse state.
+  factory Element.html(String html) {
+
+    // TODO(jacobr): this method can be made more robust and performant.
+    // 1) Cache the dummy parent elements required to use innerHTML rather than
+    //    creating them every call.
+    // 2) Verify that the html does not contain leading or trailing text nodes.
+    // 3) Verify that the html does not contain both <head> and <body> tags.
+    // 4) Detatch the created element from its dummy parent.
+    String parentTag = 'div';
+    String tag;
+    final match = _START_TAG_REGEXP.firstMatch(html);
+    if (match != null) {
+      tag = match.group(1).toLowerCase();
+      if (_CUSTOM_PARENT_TAG_MAP.containsKey(tag)) {
+        parentTag = _CUSTOM_PARENT_TAG_MAP[tag];
+      }
+    }
+
+    var fragment = parseFragment(html, container: parentTag);
+    Element element;
+    if (fragment.children.length == 1) {
+      element = fragment.children[0];
+    } else if (parentTag == 'html' && fragment.children.length == 2) {
+      // You'll always get a head and a body when starting from html.
+      element = fragment.children[tag == 'head' ? 0 : 1];
+    } else {
+      throw new ArgumentError('HTML had ${fragment.children.length} '
+          'top level elements but 1 expected');
+    }
+    element.remove();
+    return element;
+  }
+
+  int get nodeType => Node.ELEMENT_NODE;
+
+  String toString() {
+    if (namespace == null) return "<$tagName>";
+    return "<${Namespaces.getPrefix(namespace)} $tagName>";
+  }
+
+  void _addOuterHtml(StringBuffer str) {
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
+    // Element is the most complicated one.
+    if (namespace == null ||
+        namespace == Namespaces.html ||
+        namespace == Namespaces.mathml ||
+        namespace == Namespaces.svg) {
+      str.write('<$tagName');
+    } else {
+      // TODO(jmesserly): the spec doesn't define "qualified name".
+      // I'm not sure if this is correct, but it should parse reasonably.
+      str.write('<${Namespaces.getPrefix(namespace)}:$tagName');
+    }
+
+    if (attributes.length > 0) {
+      attributes.forEach((key, v) {
+        // Note: AttributeName.toString handles serialization of attribute
+        // namespace, if needed.
+        str.write(' $key="${htmlSerializeEscape(v, attributeMode: true)}"');
+      });
+    }
+
+    str.write('>');
+
+    if (nodes.length > 0) {
+      if (tagName == 'pre' || tagName == 'textarea' || tagName == 'listing') {
+        if (nodes[0] is Text && nodes[0].value.startsWith('\n')) {
+          // These nodes will remove a leading \n at parse time, so if we still
+          // have one, it means we started with two. Add it back.
+          str.write('\n');
+        }
+      }
+
+      _addInnerHtml(str);
+    }
+
+    // void elements must not have an end tag
+    // http://dev.w3.org/html5/markup/syntax.html#void-elements
+    if (!isVoidElement(tagName)) str.write('</$tagName>');
+  }
+
+  Element clone() => new Element(tagName, namespace)
+      ..attributes = new LinkedHashMap.from(attributes);
+
+  String get id {
+    var result = attributes['id'];
+    return result != null ? result : '';
+  }
+
+  set id(String value) {
+    if (value == null) {
+      attributes.remove('id');
+    } else {
+      attributes['id'] = value;
+    }
+  }
+}
+
+class Comment extends Node {
+  final String data;
+
+  Comment(this.data) : super(null);
+
+  int get nodeType => Node.COMMENT_NODE;
+
+  String toString() => "<!-- $data -->";
+
+  void _addOuterHtml(StringBuffer str) {
+    str.write("<!--$data-->");
+  }
+
+  Comment clone() => new Comment(data);
+}
+
+
+// TODO(jmesserly): fix this to extend one of the corelib classes if possible.
+// (The requirement to remove the node from the old node list makes it tricky.)
+// TODO(jmesserly): is there any way to share code with the _NodeListImpl?
+class NodeList extends ListProxy<Node> {
+  // Note: this is conceptually final, but because of circular reference
+  // between Node and NodeList we initialize it after construction.
+  Node _parent;
+
+  NodeList._();
+
+  Node get first => this[0];
+
+  Node _setParent(Node node) {
+    // Note: we need to remove the node from its previous parent node, if any,
+    // before updating its parent pointer to point at our parent.
+    node.remove();
+    node.parent = _parent;
+    return node;
+  }
+
+  void add(Node value) {
+    super.add(_setParent(value));
+  }
+
+  void addLast(Node value) => add(value);
+
+  void addAll(Iterable<Node> collection) {
+    // Note: we need to be careful if collection is another NodeList.
+    // In particular:
+    //   1. we need to copy the items before updating their parent pointers,
+    //   2. we should update parent pointers in reverse order. That way they
+    //      are removed from the original NodeList (if any) from the end, which
+    //      is faster.
+    var list = (collection is NodeList || collection is! List)
+        ? collection.toList() : collection as List;
+    for (var node in list.reversed) _setParent(node);
+    super.addAll(list);
+  }
+
+  void insert(int index, Node value) {
+    super.insert(index, _setParent(value));
+  }
+
+  Node removeLast() => super.removeLast()..parent = null;
+
+  Node removeAt(int i) => super.removeAt(i)..parent = null;
+
+  void clear() {
+    for (var node in this) node.parent = null;
+    super.clear();
+  }
+
+  void operator []=(int index, Node value) {
+    this[index].parent = null;
+    super[index] = _setParent(value);
+  }
+
+  // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see
+  // http://code.google.com/p/dart/issues/detail?id=5371
+  void setRange(int start, int rangeLength, List<Node> from,
+                [int startFrom = 0]) {
+    if (from is NodeList) {
+      // Note: this is presumed to make a copy
+      from = from.sublist(startFrom, startFrom + rangeLength);
+    }
+    // Note: see comment in [addAll]. We need to be careful about the order of
+    // operations if [from] is also a NodeList.
+    for (int i = rangeLength - 1; i >= 0; i--) {
+      this[start + i].parent = null;
+      super[start + i] = _setParent(from[startFrom + i]);
+    }
+  }
+
+  void replaceRange(int start, int end, Iterable<Node> newContents) {
+    removeRange(start, end);
+    insertAll(start, newContents);
+  }
+
+  void removeRange(int start, int rangeLength) {
+    for (int i = start; i < rangeLength; i++) this[i].parent = null;
+    super.removeRange(start, rangeLength);
+  }
+
+  void removeWhere(bool test(Element e)) {
+    for (var node in where(test)) {
+      node.parent = null;
+    }
+    super.removeWhere(test);
+  }
+
+  void retainWhere(bool test(Element e)) {
+    for (var node in where((n) => !test(n))) {
+      node.parent = null;
+    }
+    super.retainWhere(test);
+  }
+
+  void insertAll(int index, List<Node> nodes) {
+    for (var node in nodes) _setParent(node);
+    super.insertAll(index, nodes);
+  }
+}
+
+
+/**
+ * An indexable collection of a node's descendants in the document tree,
+ * filtered so that only elements are in the collection.
+ */
+// TODO(jmesserly): this was copied from dart:html
+// TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug.
+class FilteredElementList extends IterableBase<Element> with ListMixin<Element>
+    implements List<Element> {
+
+  final Node _node;
+  final List<Node> _childNodes;
+
+  /**
+   * Creates a collection of the elements that descend from a node.
+   *
+   * Example usage:
+   *
+   *     var filteredElements = new FilteredElementList(query("#container"));
+   *     // filteredElements is [a, b, c].
+   */
+  FilteredElementList(Node node): _childNodes = node.nodes, _node = node;
+
+  // We can't memoize this, since it's possible that children will be messed
+  // with externally to this class.
+  //
+  // TODO(nweiz): we don't always need to create a new list. For example
+  // forEach, every, any, ... could directly work on the _childNodes.
+  List<Element> get _filtered =>
+    new List<Element>.from(_childNodes.where((n) => n is Element));
+
+  void forEach(void f(Element element)) {
+    _filtered.forEach(f);
+  }
+
+  void operator []=(int index, Element value) {
+    this[index].replaceWith(value);
+  }
+
+  void set length(int newLength) {
+    final len = this.length;
+    if (newLength >= len) {
+      return;
+    } else if (newLength < 0) {
+      throw new ArgumentError("Invalid list length");
+    }
+
+    removeRange(newLength, len);
+  }
+
+  String join([String separator = ""]) => _filtered.join(separator);
+
+  void add(Element value) {
+    _childNodes.add(value);
+  }
+
+  void addAll(Iterable<Element> iterable) {
+    for (Element element in iterable) {
+      add(element);
+    }
+  }
+
+  bool contains(Element element) {
+    return element is Element && _childNodes.contains(element);
+  }
+
+  Iterable<Element> get reversed => _filtered.reversed;
+
+  void sort([int compare(Element a, Element b)]) {
+    throw new UnsupportedError('TODO(jacobr): should we impl?');
+  }
+
+  void setRange(int start, int end, Iterable<Element> iterable,
+                [int skipCount = 0]) {
+    throw new UnimplementedError();
+  }
+
+  void fillRange(int start, int end, [Element fillValue]) {
+    throw new UnimplementedError();
+  }
+
+  void replaceRange(int start, int end, Iterable<Element> iterable) {
+    throw new UnimplementedError();
+  }
+
+  void removeRange(int start, int end) {
+    _filtered.sublist(start, end).forEach((el) => el.remove());
+  }
+
+  void clear() {
+    // Currently, ElementList#clear clears even non-element nodes, so we follow
+    // that behavior.
+    _childNodes.clear();
+  }
+
+  Element removeLast() {
+    final result = this.last;
+    if (result != null) {
+      result.remove();
+    }
+    return result;
+  }
+
+  Iterable map(f(Element element)) => _filtered.map(f);
+  Iterable<Element> where(bool f(Element element)) => _filtered.where(f);
+  Iterable expand(Iterable f(Element element)) => _filtered.expand(f);
+
+  void insert(int index, Element value) {
+    _childNodes.insert(index, value);
+  }
+
+  void insertAll(int index, Iterable<Element> iterable) {
+    _childNodes.insertAll(index, iterable);
+  }
+
+  Element removeAt(int index) {
+    final result = this[index];
+    result.remove();
+    return result;
+  }
+
+  bool remove(Object element) {
+    if (element is! Element) return false;
+    for (int i = 0; i < length; i++) {
+      Element indexElement = this[i];
+      if (identical(indexElement, element)) {
+        indexElement.remove();
+        return true;
+      }
+    }
+    return false;
+  }
+
+  Element reduce(Element combine(Element value, Element element)) {
+    return _filtered.reduce(combine);
+  }
+
+  dynamic fold(dynamic initialValue,
+      dynamic combine(dynamic previousValue, Element element)) {
+    return _filtered.fold(initialValue, combine);
+  }
+
+  bool every(bool f(Element element)) => _filtered.every(f);
+  bool any(bool f(Element element)) => _filtered.any(f);
+  List<Element> toList({ bool growable: true }) =>
+      new List<Element>.from(this, growable: growable);
+  Set<Element> toSet() => new Set<Element>.from(this);
+  Element firstWhere(bool test(Element value), {Element orElse()}) {
+    return _filtered.firstWhere(test, orElse: orElse);
+  }
+
+  Element lastWhere(bool test(Element value), {Element orElse()}) {
+    return _filtered.lastWhere(test, orElse: orElse);
+  }
+
+  Element singleWhere(bool test(Element value)) {
+    return _filtered.singleWhere(test);
+  }
+
+  Element elementAt(int index) {
+    return this[index];
+  }
+
+  bool get isEmpty => _filtered.isEmpty;
+  int get length => _filtered.length;
+  Element operator [](int index) => _filtered[index];
+  Iterator<Element> get iterator => _filtered.iterator;
+  List<Element> sublist(int start, [int end]) =>
+    _filtered.sublist(start, end);
+  Iterable<Element> getRange(int start, int end) =>
+    _filtered.getRange(start, end);
+  int indexOf(Element element, [int start = 0]) =>
+    _filtered.indexOf(element, start);
+
+  int lastIndexOf(Element element, [int start = null]) {
+    if (start == null) start = length - 1;
+    return _filtered.lastIndexOf(element, start);
+  }
+
+  Element get first => _filtered.first;
+
+  Element get last => _filtered.last;
+
+  Element get single => _filtered.single;
+}
diff --git a/pkg/third_party/html5lib/lib/dom_parsing.dart b/pkg/third_party/html5lib/lib/dom_parsing.dart
new file mode 100644
index 0000000..91b37ec
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/dom_parsing.dart
@@ -0,0 +1,176 @@
+/**
+ * This library contains extra APIs that aren't in the DOM, but are useful
+ * when interacting with the parse tree.
+ */
+library dom_parsing;
+
+import 'dart:math';
+import 'dart:utf' show codepointsToString;
+import 'dom.dart';
+
+/** A simple tree visitor for the DOM nodes. */
+class TreeVisitor {
+  visit(Node node) {
+    switch (node.nodeType) {
+      case Node.ELEMENT_NODE: return visitElement(node);
+      case Node.TEXT_NODE: return visitText(node);
+      case Node.COMMENT_NODE: return visitComment(node);
+      case Node.DOCUMENT_FRAGMENT_NODE: return visitDocumentFragment(node);
+      case Node.DOCUMENT_NODE: return visitDocument(node);
+      case Node.DOCUMENT_TYPE_NODE: return visitDocumentType(node);
+      default: throw new UnsupportedError('DOM node type ${node.nodeType}');
+    }
+  }
+
+  visitChildren(Node node) {
+    // Allow for mutations (remove works) while iterating.
+    for (var child in node.nodes.toList()) visit(child);
+  }
+
+  /**
+   * The fallback handler if the more specific visit method hasn't been
+   * overriden. Only use this from a subclass of [TreeVisitor], otherwise
+   * call [visit] instead.
+   */
+  visitNodeFallback(Node node) => visitChildren(node);
+
+  visitDocument(Document node) => visitNodeFallback(node);
+
+  visitDocumentType(DocumentType node) => visitNodeFallback(node);
+
+  visitText(Text node) => visitNodeFallback(node);
+
+  // TODO(jmesserly): visit attributes.
+  visitElement(Element node) => visitNodeFallback(node);
+
+  visitComment(Comment node) => visitNodeFallback(node);
+
+  // Note: visits document by default because DocumentFragment is a Document.
+  visitDocumentFragment(DocumentFragment node) => visitDocument(node);
+}
+
+/**
+ * Converts the DOM tree into an HTML string with code markup suitable for
+ * displaying the HTML's source code with CSS colors for different parts of the
+ * markup. See also [CodeMarkupVisitor].
+ */
+String htmlToCodeMarkup(Node node) {
+  return (new CodeMarkupVisitor()..visit(node)).toString();
+}
+
+/**
+ * Converts the DOM tree into an HTML string with code markup suitable for
+ * displaying the HTML's source code with CSS colors for different parts of the
+ * markup. See also [htmlToCodeMarkup].
+ */
+class CodeMarkupVisitor extends TreeVisitor {
+  final StringBuffer _str;
+
+  CodeMarkupVisitor() : _str = new StringBuffer();
+
+  String toString() => _str.toString();
+
+  visitDocument(Document node) {
+    _str.write("<pre>");
+    visitChildren(node);
+    _str.write("</pre>");
+  }
+
+  visitDocumentType(DocumentType node) {
+    _str.write('<code class="markup doctype">&lt;!DOCTYPE ${node.tagName}>'
+        '</code>');
+  }
+
+  visitText(Text node) {
+    // TODO(jmesserly): would be nice to use _addOuterHtml directly.
+    _str.write(node.outerHtml);
+  }
+
+  visitElement(Element node) {
+    _str.write('&lt;<code class="markup element-name">${node.tagName}</code>');
+    if (node.attributes.length > 0) {
+      node.attributes.forEach((key, v) {
+        v = htmlSerializeEscape(v, attributeMode: true);
+        _str.write(' <code class="markup attribute-name">$key</code>'
+            '=<code class="markup attribute-value">"$v"</code>');
+      });
+    }
+    if (node.nodes.length > 0) {
+      _str.write(">");
+      visitChildren(node);
+    } else if (isVoidElement(node.tagName)) {
+      _str.write(">");
+      return;
+    }
+    _str.write(
+        '&lt;/<code class="markup element-name">${node.tagName}</code>>');
+  }
+
+  visitComment(Comment node) {
+    var data = htmlSerializeEscape(node.data);
+    _str.write('<code class="markup comment">&lt;!--${data}--></code>');
+  }
+}
+
+
+// TODO(jmesserly): reconcile this with dart:web htmlEscape.
+// This one might be more useful, as it is HTML5 spec compliant.
+/**
+ * Escapes [text] for use in the
+ * [HTML fragment serialization algorithm][1]. In particular, as described
+ * in the [specification][2]:
+ *
+ * - Replace any occurrence of the `&` character by the string `&amp;`.
+ * - Replace any occurrences of the U+00A0 NO-BREAK SPACE character by the
+ *   string `&nbsp;`.
+ * - If the algorithm was invoked in [attributeMode], replace any occurrences of
+ *   the `"` character by the string `&quot;`.
+ * - If the algorithm was not invoked in [attributeMode], replace any
+ *   occurrences of the `<` character by the string `&lt;`, and any occurrences
+ *   of the `>` character by the string `&gt;`.
+ *
+ * [1]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
+ * [2]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
+ */
+String htmlSerializeEscape(String text, {bool attributeMode: false}) {
+  // TODO(jmesserly): is it faster to build up a list of codepoints?
+  // StringBuffer seems cleaner assuming Dart can unbox 1-char strings.
+  StringBuffer result = null;
+  for (int i = 0; i < text.length; i++) {
+    var ch = text[i];
+    String replace = null;
+    switch (ch) {
+      case '&': replace = '&amp;'; break;
+      case '\u00A0'/*NO-BREAK SPACE*/: replace = '&nbsp;'; break;
+      case '"': if (attributeMode) replace = '&quot;'; break;
+      case '<': if (!attributeMode) replace = '&lt;'; break;
+      case '>': if (!attributeMode) replace = '&gt;'; break;
+    }
+    if (replace != null) {
+      if (result == null) result = new StringBuffer(text.substring(0, i));
+      result.write(replace);
+    } else if (result != null) {
+      result.write(ch);
+    }
+  }
+
+  return result != null ? result.toString() : text;
+}
+
+
+/**
+ * Returns true if this tag name is a void element.
+ * This method is useful to a pretty printer, because void elements must not
+ * have an end tag.
+ * See <http://dev.w3.org/html5/markup/syntax.html#void-elements> for more info.
+ */
+bool isVoidElement(String tagName) {
+  switch (tagName) {
+    case "area": case "base": case "br": case "col": case "command":
+    case "embed": case "hr": case "img": case "input": case "keygen":
+    case "link": case "meta": case "param": case "source": case "track":
+    case "wbr":
+      return true;
+  }
+  return false;
+}
diff --git a/pkg/third_party/html5lib/lib/parser.dart b/pkg/third_party/html5lib/lib/parser.dart
new file mode 100644
index 0000000..268053a
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/parser.dart
@@ -0,0 +1,3345 @@
+/**
+ * This library has a parser for HTML5 documents, that lets you parse HTML
+ * easily from a script or server side application:
+ *
+ *     import 'package:html5lib/parser.dart' show parse;
+ *     import 'package:html5lib/dom.dart';
+ *     main() {
+ *       var document = parse(
+ *           '<body>Hello world! <a href="www.html5rocks.com">HTML5 rocks!');
+ *       print(document.outerHtml);
+ *     }
+ *
+ * The resulting document you get back has a DOM-like API for easy tree
+ * traversal and manipulation.
+ */
+library parser;
+
+import 'dart:collection';
+import 'dart:math';
+import 'package:source_maps/span.dart' show Span, FileSpan;
+
+import 'src/treebuilder.dart';
+import 'src/constants.dart';
+import 'src/encoding_parser.dart';
+import 'src/token.dart';
+import 'src/tokenizer.dart';
+import 'src/utils.dart';
+import 'dom.dart';
+import 'dom_parsing.dart';
+
+/**
+ * Parse the [input] html5 document into a tree. The [input] can be
+ * a [String], [List<int>] of bytes or an [HtmlTokenizer].
+ *
+ * If [input] is not a [HtmlTokenizer], you can optionally specify the file's
+ * [encoding], which must be a string. If specified, that encoding will be used,
+ * regardless of any BOM or later declaration (such as in a meta element).
+ *
+ * Set [generateSpans] if you want to generate [Span]s, otherwise the
+ * [Node.sourceSpan] property will be `null`. When using [generateSpans] you can
+ * additionally pass [sourceUrl] to indicate where the [input] was extracted
+ * from.
+ */
+Document parse(input, {String encoding, bool generateSpans: false,
+    String sourceUrl}) {
+  var p = new HtmlParser(input, encoding: encoding,
+      generateSpans: generateSpans, sourceUrl: sourceUrl);
+  return p.parse();
+}
+
+
+/**
+ * Parse the [input] html5 document fragment into a tree. The [input] can be
+ * a [String], [List<int>] of bytes or an [HtmlTokenizer]. The [container]
+ * element can optionally be specified, otherwise it defaults to "div".
+ *
+ * If [input] is not a [HtmlTokenizer], you can optionally specify the file's
+ * [encoding], which must be a string. If specified, that encoding will be used,
+ * regardless of any BOM or later declaration (such as in a meta element).
+ *
+ * Set [generateSpans] if you want to generate [Span]s, otherwise the
+ * [Node.sourceSpan] property will be `null`. When using [generateSpans] you can
+ * additionally pass [sourceUrl] to indicate where the [input] was extracted
+ * from.
+ */
+DocumentFragment parseFragment(input, {String container: "div",
+    String encoding, bool generateSpans: false, String sourceUrl}) {
+  var p = new HtmlParser(input, encoding: encoding,
+      generateSpans: generateSpans, sourceUrl: sourceUrl);
+  return p.parseFragment(container);
+}
+
+
+/**
+ * Parser for HTML, which generates a tree structure from a stream of
+ * (possibly malformed) characters.
+ */
+class HtmlParser {
+  /** Raise an exception on the first error encountered. */
+  final bool strict;
+
+  /** True to generate [Span]s for the [Node.sourceSpan] property. */
+  final bool generateSpans;
+
+  final HtmlTokenizer tokenizer;
+
+  final TreeBuilder tree;
+
+  final List<ParseError> errors = <ParseError>[];
+
+  String container;
+
+  bool firstStartTag = false;
+
+  // TODO(jmesserly): use enum?
+  /** "quirks" / "limited quirks" / "no quirks" */
+  String compatMode = "no quirks";
+
+  /** innerHTML container when parsing document fragment. */
+  String innerHTML;
+
+  Phase phase;
+
+  Phase lastPhase;
+
+  Phase originalPhase;
+
+  Phase beforeRCDataPhase;
+
+  bool framesetOK;
+
+  // These fields hold the different phase singletons. At any given time one
+  // of them will be active.
+  InitialPhase _initialPhase;
+  BeforeHtmlPhase _beforeHtmlPhase;
+  BeforeHeadPhase _beforeHeadPhase;
+  InHeadPhase _inHeadPhase;
+  AfterHeadPhase _afterHeadPhase;
+  InBodyPhase _inBodyPhase;
+  TextPhase _textPhase;
+  InTablePhase _inTablePhase;
+  InTableTextPhase _inTableTextPhase;
+  InCaptionPhase _inCaptionPhase;
+  InColumnGroupPhase _inColumnGroupPhase;
+  InTableBodyPhase _inTableBodyPhase;
+  InRowPhase _inRowPhase;
+  InCellPhase _inCellPhase;
+  InSelectPhase _inSelectPhase;
+  InSelectInTablePhase _inSelectInTablePhase;
+  InForeignContentPhase _inForeignContentPhase;
+  AfterBodyPhase _afterBodyPhase;
+  InFramesetPhase _inFramesetPhase;
+  AfterFramesetPhase _afterFramesetPhase;
+  AfterAfterBodyPhase _afterAfterBodyPhase;
+  AfterAfterFramesetPhase _afterAfterFramesetPhase;
+
+  /**
+   * Create a new HtmlParser and configure the [tree] builder and [strict] mode.
+   * The [input] can be a [String], [List<int>] of bytes or an [HtmlTokenizer].
+   *
+   * If [input] is not a [HtmlTokenizer], you can specify a few more arguments.
+   *
+   * The [encoding] must be a string that indicates the encoding. If specified,
+   * that encoding will be used, regardless of any BOM or later declaration
+   * (such as in a meta element).
+   *
+   * Set [parseMeta] to false if you want to disable parsing the meta element.
+   *
+   * Set [lowercaseElementName] or [lowercaseAttrName] to false to disable the
+   * automatic conversion of element and attribute names to lower case. Note
+   * that standard way to parse HTML is to lowercase, which is what the browser
+   * DOM will do if you request [Node.outerHTML], for example.
+   */
+  HtmlParser(input, {String encoding, bool parseMeta: true,
+      bool lowercaseElementName: true, bool lowercaseAttrName: true,
+      this.strict: false, bool generateSpans: false, String sourceUrl,
+      TreeBuilder tree})
+      : generateSpans = generateSpans,
+        tree = tree != null ? tree : new TreeBuilder(true),
+        tokenizer = (input is HtmlTokenizer ? input :
+          new HtmlTokenizer(input, encoding: encoding, parseMeta: parseMeta,
+            lowercaseElementName: lowercaseElementName,
+            lowercaseAttrName: lowercaseAttrName,
+            generateSpans: generateSpans, sourceUrl: sourceUrl)) {
+
+    tokenizer.parser = this;
+    _initialPhase = new InitialPhase(this);
+    _beforeHtmlPhase = new BeforeHtmlPhase(this);
+    _beforeHeadPhase = new BeforeHeadPhase(this);
+    _inHeadPhase = new InHeadPhase(this);
+    // TODO(jmesserly): html5lib did not implement the no script parsing mode
+    // More information here:
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#scripting-flag
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inheadnoscript
+    // "inHeadNoscript": new InHeadNoScriptPhase(this);
+    _afterHeadPhase = new AfterHeadPhase(this);
+    _inBodyPhase = new InBodyPhase(this);
+    _textPhase = new TextPhase(this);
+    _inTablePhase = new InTablePhase(this);
+    _inTableTextPhase = new InTableTextPhase(this);
+    _inCaptionPhase = new InCaptionPhase(this);
+    _inColumnGroupPhase = new InColumnGroupPhase(this);
+    _inTableBodyPhase = new InTableBodyPhase(this);
+    _inRowPhase = new InRowPhase(this);
+    _inCellPhase = new InCellPhase(this);
+    _inSelectPhase = new InSelectPhase(this);
+    _inSelectInTablePhase = new InSelectInTablePhase(this);
+    _inForeignContentPhase = new InForeignContentPhase(this);
+    _afterBodyPhase = new AfterBodyPhase(this);
+    _inFramesetPhase = new InFramesetPhase(this);
+    _afterFramesetPhase = new AfterFramesetPhase(this);
+    _afterAfterBodyPhase = new AfterAfterBodyPhase(this);
+    _afterAfterFramesetPhase = new AfterAfterFramesetPhase(this);
+  }
+
+  bool get innerHTMLMode => innerHTML != null;
+
+  /**
+   * Parse an html5 document into a tree.
+   * After parsing, [errors] will be populated with parse errors, if any.
+   */
+  Document parse() {
+    innerHTML = null;
+    _parse();
+    return tree.getDocument();
+  }
+
+  /**
+   * Parse an html5 document fragment into a tree.
+   * Pass a [container] to change the type of the containing element.
+   * After parsing, [errors] will be populated with parse errors, if any.
+   */
+  DocumentFragment parseFragment([String container = "div"]) {
+    if (container == null) throw new ArgumentError('container');
+    innerHTML = container.toLowerCase();
+    _parse();
+    return tree.getFragment();
+  }
+
+  void _parse() {
+    reset();
+
+    while (true) {
+      try {
+        mainLoop();
+        break;
+      } on ReparseException catch (e) {
+        // Note: this happens if we start parsing but the character encoding
+        // changes. So we should only need to restart very early in the parse.
+        reset();
+      }
+    }
+  }
+
+  void reset() {
+    tokenizer.reset();
+
+    tree.reset();
+    firstStartTag = false;
+    errors.clear();
+    // "quirks" / "limited quirks" / "no quirks"
+    compatMode = "no quirks";
+
+    if (innerHTMLMode) {
+      if (cdataElements.contains(innerHTML)) {
+        tokenizer.state = tokenizer.rcdataState;
+      } else if (rcdataElements.contains(innerHTML)) {
+        tokenizer.state = tokenizer.rawtextState;
+      } else if (innerHTML == 'plaintext') {
+        tokenizer.state = tokenizer.plaintextState;
+      } else {
+        // state already is data state
+        // tokenizer.state = tokenizer.dataState;
+      }
+      phase = _beforeHtmlPhase;
+      _beforeHtmlPhase.insertHtmlElement();
+      resetInsertionMode();
+    } else {
+      phase = _initialPhase;
+    }
+
+    lastPhase = null;
+    beforeRCDataPhase = null;
+    framesetOK = true;
+  }
+
+  bool isHTMLIntegrationPoint(Node element) {
+    if (element.tagName == "annotation-xml" &&
+        element.namespace == Namespaces.mathml) {
+      var enc = element.attributes["encoding"];
+      if (enc != null) enc = asciiUpper2Lower(enc);
+      return enc == "text/html" || enc == "application/xhtml+xml";
+    } else {
+      return htmlIntegrationPointElements.contains(
+          new Pair(element.namespace, element.tagName));
+    }
+  }
+
+  bool isMathMLTextIntegrationPoint(Node element) {
+    return mathmlTextIntegrationPointElements.contains(
+        new Pair(element.namespace, element.tagName));
+  }
+
+  bool inForeignContent(Token token, int type) {
+    if (tree.openElements.length == 0) return false;
+
+    var node = tree.openElements.last;
+    if (node.namespace == tree.defaultNamespace) return false;
+
+    if (isMathMLTextIntegrationPoint(node)) {
+      if (type == TokenKind.startTag &&
+          (token as StartTagToken).name != "mglyph" &&
+          (token as StartTagToken).name != "malignmark")  {
+        return false;
+      }
+      if (type == TokenKind.characters || type == TokenKind.spaceCharacters) {
+        return false;
+      }
+    }
+
+    if (node.tagName == "annotation-xml" && type == TokenKind.startTag &&
+        (token as StartTagToken).name == "svg") {
+      return false;
+    }
+
+    if (isHTMLIntegrationPoint(node)) {
+      if (type == TokenKind.startTag ||
+          type == TokenKind.characters ||
+          type == TokenKind.spaceCharacters) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  void mainLoop() {
+    while (tokenizer.moveNext()) {
+      var token = tokenizer.current;
+      var newToken = token;
+      int type;
+      while (newToken != null) {
+        type = newToken.kind;
+
+        // Note: avoid "is" test here, see http://dartbug.com/4795
+        if (type == TokenKind.parseError) {
+          ParseErrorToken error = newToken;
+          parseError(error.span, error.data, error.messageParams);
+          newToken = null;
+        } else {
+          Phase phase_ = phase;
+          if (inForeignContent(token, type)) {
+            phase_ = _inForeignContentPhase;
+          }
+
+          switch (type) {
+            case TokenKind.characters:
+              newToken = phase_.processCharacters(newToken);
+              break;
+            case TokenKind.spaceCharacters:
+              newToken = phase_.processSpaceCharacters(newToken);
+              break;
+            case TokenKind.startTag:
+              newToken = phase_.processStartTag(newToken);
+              break;
+            case TokenKind.endTag:
+              newToken = phase_.processEndTag(newToken);
+              break;
+            case TokenKind.comment:
+              newToken = phase_.processComment(newToken);
+              break;
+            case TokenKind.doctype:
+              newToken = phase_.processDoctype(newToken);
+              break;
+          }
+        }
+      }
+
+      if (token is StartTagToken) {
+        if (token.selfClosing && !token.selfClosingAcknowledged) {
+          parseError(token.span, "non-void-element-with-trailing-solidus",
+              {"name": token.name});
+        }
+      }
+    }
+
+    // When the loop finishes it's EOF
+    var reprocess = true;
+    var reprocessPhases = [];
+    while (reprocess) {
+      reprocessPhases.add(phase);
+      reprocess = phase.processEOF();
+      if (reprocess) {
+        assert(!reprocessPhases.contains(phase));
+      }
+    }
+  }
+
+  /**
+   * The last span available. Used for EOF errors if we don't have something
+   * better.
+   */
+  Span get _lastSpan {
+    var pos = tokenizer.stream.position;
+    return new FileSpan(tokenizer.stream.fileInfo, pos, pos);
+  }
+
+  void parseError(Span span, String errorcode,
+      [Map datavars = const {}]) {
+
+    if (!generateSpans && span == null) {
+      span = _lastSpan;
+    }
+
+    var err = new ParseError(errorcode, span, datavars);
+    errors.add(err);
+    if (strict) throw err;
+  }
+
+  void adjustMathMLAttributes(StartTagToken token) {
+    var orig = token.data.remove("definitionurl");
+    if (orig != null) {
+      token.data["definitionURL"] = orig;
+    }
+  }
+
+  void adjustSVGAttributes(StartTagToken token) {
+    final replacements = const {
+      "attributename":"attributeName",
+      "attributetype":"attributeType",
+      "basefrequency":"baseFrequency",
+      "baseprofile":"baseProfile",
+      "calcmode":"calcMode",
+      "clippathunits":"clipPathUnits",
+      "contentscripttype":"contentScriptType",
+      "contentstyletype":"contentStyleType",
+      "diffuseconstant":"diffuseConstant",
+      "edgemode":"edgeMode",
+      "externalresourcesrequired":"externalResourcesRequired",
+      "filterres":"filterRes",
+      "filterunits":"filterUnits",
+      "glyphref":"glyphRef",
+      "gradienttransform":"gradientTransform",
+      "gradientunits":"gradientUnits",
+      "kernelmatrix":"kernelMatrix",
+      "kernelunitlength":"kernelUnitLength",
+      "keypoints":"keyPoints",
+      "keysplines":"keySplines",
+      "keytimes":"keyTimes",
+      "lengthadjust":"lengthAdjust",
+      "limitingconeangle":"limitingConeAngle",
+      "markerheight":"markerHeight",
+      "markerunits":"markerUnits",
+      "markerwidth":"markerWidth",
+      "maskcontentunits":"maskContentUnits",
+      "maskunits":"maskUnits",
+      "numoctaves":"numOctaves",
+      "pathlength":"pathLength",
+      "patterncontentunits":"patternContentUnits",
+      "patterntransform":"patternTransform",
+      "patternunits":"patternUnits",
+      "pointsatx":"pointsAtX",
+      "pointsaty":"pointsAtY",
+      "pointsatz":"pointsAtZ",
+      "preservealpha":"preserveAlpha",
+      "preserveaspectratio":"preserveAspectRatio",
+      "primitiveunits":"primitiveUnits",
+      "refx":"refX",
+      "refy":"refY",
+      "repeatcount":"repeatCount",
+      "repeatdur":"repeatDur",
+      "requiredextensions":"requiredExtensions",
+      "requiredfeatures":"requiredFeatures",
+      "specularconstant":"specularConstant",
+      "specularexponent":"specularExponent",
+      "spreadmethod":"spreadMethod",
+      "startoffset":"startOffset",
+      "stddeviation":"stdDeviation",
+      "stitchtiles":"stitchTiles",
+      "surfacescale":"surfaceScale",
+      "systemlanguage":"systemLanguage",
+      "tablevalues":"tableValues",
+      "targetx":"targetX",
+      "targety":"targetY",
+      "textlength":"textLength",
+      "viewbox":"viewBox",
+      "viewtarget":"viewTarget",
+      "xchannelselector":"xChannelSelector",
+      "ychannelselector":"yChannelSelector",
+      "zoomandpan":"zoomAndPan"
+    };
+    for (var originalName in token.data.keys.toList()) {
+      var svgName = replacements[originalName];
+      if (svgName != null) {
+        token.data[svgName] = token.data.remove(originalName);
+      }
+    }
+  }
+
+  void adjustForeignAttributes(StartTagToken token) {
+    // TODO(jmesserly): I don't like mixing non-string objects with strings in
+    // the Node.attributes Map. Is there another solution?
+    final replacements = const {
+      "xlink:actuate": const AttributeName("xlink", "actuate",
+            Namespaces.xlink),
+      "xlink:arcrole": const AttributeName("xlink", "arcrole",
+            Namespaces.xlink),
+      "xlink:href": const AttributeName("xlink", "href", Namespaces.xlink),
+      "xlink:role": const AttributeName("xlink", "role", Namespaces.xlink),
+      "xlink:show": const AttributeName("xlink", "show", Namespaces.xlink),
+      "xlink:title": const AttributeName("xlink", "title", Namespaces.xlink),
+      "xlink:type": const AttributeName("xlink", "type", Namespaces.xlink),
+      "xml:base": const AttributeName("xml", "base", Namespaces.xml),
+      "xml:lang": const AttributeName("xml", "lang", Namespaces.xml),
+      "xml:space": const AttributeName("xml", "space", Namespaces.xml),
+      "xmlns": const AttributeName(null, "xmlns", Namespaces.xmlns),
+      "xmlns:xlink": const AttributeName("xmlns", "xlink", Namespaces.xmlns)
+    };
+
+    for (var originalName in token.data.keys.toList()) {
+      var foreignName = replacements[originalName];
+      if (foreignName != null) {
+        token.data[foreignName] = token.data.remove(originalName);
+      }
+    }
+  }
+
+  void resetInsertionMode() {
+    // The name of this method is mostly historical. (It's also used in the
+    // specification.)
+    for (Node node in tree.openElements.reversed) {
+      var nodeName = node.tagName;
+      bool last = node == tree.openElements[0];
+      if (last) {
+        assert(innerHTMLMode);
+        nodeName = innerHTML;
+      }
+      // Check for conditions that should only happen in the innerHTML
+      // case
+      switch (nodeName) {
+        case "select": case "colgroup": case "head": case "html":
+          assert(innerHTMLMode);
+          break;
+      }
+      if (!last && node.namespace != tree.defaultNamespace) {
+        continue;
+      }
+      switch (nodeName) {
+        case "select": phase = _inSelectPhase; return;
+        case "td": phase = _inCellPhase; return;
+        case "th": phase = _inCellPhase; return;
+        case "tr": phase = _inRowPhase; return;
+        case "tbody": phase = _inTableBodyPhase; return;
+        case "thead": phase = _inTableBodyPhase; return;
+        case "tfoot": phase = _inTableBodyPhase; return;
+        case "caption": phase = _inCaptionPhase; return;
+        case "colgroup": phase = _inColumnGroupPhase; return;
+        case "table": phase = _inTablePhase; return;
+        case "head": phase = _inBodyPhase; return;
+        case "body": phase = _inBodyPhase; return;
+        case "frameset": phase = _inFramesetPhase; return;
+        case "html": phase = _beforeHeadPhase; return;
+      }
+    }
+    phase = _inBodyPhase;
+  }
+
+  /**
+   * Generic RCDATA/RAWTEXT Parsing algorithm
+   * [contentType] - RCDATA or RAWTEXT
+   */
+  void parseRCDataRawtext(Token token, String contentType) {
+    assert(contentType == "RAWTEXT" || contentType == "RCDATA");
+
+    var element = tree.insertElement(token);
+
+    if (contentType == "RAWTEXT") {
+      tokenizer.state = tokenizer.rawtextState;
+    } else {
+      tokenizer.state = tokenizer.rcdataState;
+    }
+
+    originalPhase = phase;
+    phase = _textPhase;
+  }
+}
+
+
+/** Base class for helper object that implements each phase of processing. */
+class Phase {
+  // Order should be (they can be omitted):
+  // * EOF
+  // * Comment
+  // * Doctype
+  // * SpaceCharacters
+  // * Characters
+  // * StartTag
+  //   - startTag* methods
+  // * EndTag
+  //   - endTag* methods
+
+  final HtmlParser parser;
+
+  final TreeBuilder tree;
+
+  Phase(HtmlParser parser) : parser = parser, tree = parser.tree;
+
+  bool processEOF() {
+    throw new UnimplementedError();
+  }
+
+  Token processComment(CommentToken token) {
+    // For most phases the following is correct. Where it's not it will be
+    // overridden.
+    tree.insertComment(token, tree.openElements.last);
+  }
+
+  Token processDoctype(DoctypeToken token) {
+    parser.parseError(token.span, "unexpected-doctype");
+  }
+
+  Token processCharacters(CharactersToken token) {
+    tree.insertText(token.data, token.span);
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    tree.insertText(token.data, token.span);
+  }
+
+  Token processStartTag(StartTagToken token) {
+    throw new UnimplementedError();
+  }
+
+  Token startTagHtml(StartTagToken token) {
+    if (parser.firstStartTag == false && token.name == "html") {
+       parser.parseError(token.span, "non-html-root");
+    }
+    // XXX Need a check here to see if the first start tag token emitted is
+    // this token... If it's not, invoke parser.parseError().
+    token.data.forEach((attr, value) {
+      tree.openElements[0].attributes.putIfAbsent(attr, () => value);
+    });
+    parser.firstStartTag = false;
+  }
+
+  Token processEndTag(EndTagToken token) {
+    throw new UnimplementedError();
+  }
+
+  /** Helper method for popping openElements. */
+  void popOpenElementsUntil(String name) {
+    var node = tree.openElements.removeLast();
+    while (node.tagName != name) {
+      node = tree.openElements.removeLast();
+    }
+  }
+}
+
+class InitialPhase extends Phase {
+  InitialPhase(parser) : super(parser);
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+  }
+
+  Token processComment(CommentToken token) {
+    tree.insertComment(token, tree.document);
+  }
+
+  Token processDoctype(DoctypeToken token) {
+    var name = token.name;
+    String publicId = token.publicId;
+    var systemId = token.systemId;
+    var correct = token.correct;
+
+    if ((name != "html" || publicId != null ||
+        systemId != null && systemId != "about:legacy-compat")) {
+      parser.parseError(token.span, "unknown-doctype");
+    }
+
+    if (publicId == null) {
+      publicId = "";
+    }
+
+    tree.insertDoctype(token);
+
+    if (publicId != "") {
+      publicId = asciiUpper2Lower(publicId);
+    }
+
+    if (!correct || token.name != "html"
+        || startsWithAny(publicId, const [
+          "+//silmaril//dtd html pro v0r11 19970101//",
+          "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
+          "-//as//dtd html 3.0 aswedit + extensions//",
+          "-//ietf//dtd html 2.0 level 1//",
+          "-//ietf//dtd html 2.0 level 2//",
+          "-//ietf//dtd html 2.0 strict level 1//",
+          "-//ietf//dtd html 2.0 strict level 2//",
+          "-//ietf//dtd html 2.0 strict//",
+          "-//ietf//dtd html 2.0//",
+          "-//ietf//dtd html 2.1e//",
+          "-//ietf//dtd html 3.0//",
+          "-//ietf//dtd html 3.2 final//",
+          "-//ietf//dtd html 3.2//",
+          "-//ietf//dtd html 3//",
+          "-//ietf//dtd html level 0//",
+          "-//ietf//dtd html level 1//",
+          "-//ietf//dtd html level 2//",
+          "-//ietf//dtd html level 3//",
+          "-//ietf//dtd html strict level 0//",
+          "-//ietf//dtd html strict level 1//",
+          "-//ietf//dtd html strict level 2//",
+          "-//ietf//dtd html strict level 3//",
+          "-//ietf//dtd html strict//",
+          "-//ietf//dtd html//",
+          "-//metrius//dtd metrius presentational//",
+          "-//microsoft//dtd internet explorer 2.0 html strict//",
+          "-//microsoft//dtd internet explorer 2.0 html//",
+          "-//microsoft//dtd internet explorer 2.0 tables//",
+          "-//microsoft//dtd internet explorer 3.0 html strict//",
+          "-//microsoft//dtd internet explorer 3.0 html//",
+          "-//microsoft//dtd internet explorer 3.0 tables//",
+          "-//netscape comm. corp.//dtd html//",
+          "-//netscape comm. corp.//dtd strict html//",
+          "-//o'reilly and associates//dtd html 2.0//",
+          "-//o'reilly and associates//dtd html extended 1.0//",
+          "-//o'reilly and associates//dtd html extended relaxed 1.0//",
+          "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
+          "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
+          "-//spyglass//dtd html 2.0 extended//",
+          "-//sq//dtd html 2.0 hotmetal + extensions//",
+          "-//sun microsystems corp.//dtd hotjava html//",
+          "-//sun microsystems corp.//dtd hotjava strict html//",
+          "-//w3c//dtd html 3 1995-03-24//",
+          "-//w3c//dtd html 3.2 draft//",
+          "-//w3c//dtd html 3.2 final//",
+          "-//w3c//dtd html 3.2//",
+          "-//w3c//dtd html 3.2s draft//",
+          "-//w3c//dtd html 4.0 frameset//",
+          "-//w3c//dtd html 4.0 transitional//",
+          "-//w3c//dtd html experimental 19960712//",
+          "-//w3c//dtd html experimental 970421//",
+          "-//w3c//dtd w3 html//",
+          "-//w3o//dtd w3 html 3.0//",
+          "-//webtechs//dtd mozilla html 2.0//",
+          "-//webtechs//dtd mozilla html//"])
+        || const ["-//w3o//dtd w3 html strict 3.0//en//",
+           "-/w3c/dtd html 4.0 transitional/en",
+           "html"].contains(publicId)
+        || startsWithAny(publicId, const [
+           "-//w3c//dtd html 4.01 frameset//",
+           "-//w3c//dtd html 4.01 transitional//"]) && systemId == null
+        || systemId != null && systemId.toLowerCase() ==
+           "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
+
+      parser.compatMode = "quirks";
+    } else if (startsWithAny(publicId, const [
+          "-//w3c//dtd xhtml 1.0 frameset//",
+          "-//w3c//dtd xhtml 1.0 transitional//"])
+        || startsWithAny(publicId, const [
+          "-//w3c//dtd html 4.01 frameset//",
+          "-//w3c//dtd html 4.01 transitional//"]) &&
+          systemId != null) {
+      parser.compatMode = "limited quirks";
+    }
+    parser.phase = parser._beforeHtmlPhase;
+  }
+
+  void anythingElse() {
+    parser.compatMode = "quirks";
+    parser.phase = parser._beforeHtmlPhase;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    parser.parseError(token.span, "expected-doctype-but-got-chars");
+    anythingElse();
+    return token;
+  }
+
+  Token processStartTag(StartTagToken token) {
+    parser.parseError(token.span, "expected-doctype-but-got-start-tag",
+        {"name": token.name});
+    anythingElse();
+    return token;
+  }
+
+  Token processEndTag(EndTagToken token) {
+    parser.parseError(token.span, "expected-doctype-but-got-end-tag",
+        {"name": token.name});
+    anythingElse();
+    return token;
+  }
+
+  bool processEOF() {
+    parser.parseError(parser._lastSpan, "expected-doctype-but-got-eof");
+    anythingElse();
+    return true;
+  }
+}
+
+
+class BeforeHtmlPhase extends Phase {
+  BeforeHtmlPhase(parser) : super(parser);
+
+  // helper methods
+  void insertHtmlElement() {
+    tree.insertRoot(new StartTagToken("html", data: {}));
+    parser.phase = parser._beforeHeadPhase;
+  }
+
+  // other
+  bool processEOF() {
+    insertHtmlElement();
+    return true;
+  }
+
+  Token processComment(CommentToken token) {
+    tree.insertComment(token, tree.document);
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+  }
+
+  Token processCharacters(CharactersToken token) {
+    insertHtmlElement();
+    return token;
+  }
+
+  Token processStartTag(StartTagToken token) {
+    if (token.name == "html") {
+      parser.firstStartTag = true;
+    }
+    insertHtmlElement();
+    return token;
+  }
+
+  Token processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "head": case "body": case "html": case "br":
+        insertHtmlElement();
+        return token;
+      default:
+        parser.parseError(token.span, "unexpected-end-tag-before-html",
+            {"name": token.name});
+        return null;
+    }
+  }
+}
+
+
+class BeforeHeadPhase extends Phase {
+  BeforeHeadPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case 'html': return startTagHtml(token);
+      case 'head': return startTagHead(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "head": case "body": case "html": case "br":
+        return endTagImplyHead(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  bool processEOF() {
+    startTagHead(new StartTagToken("head", data: {}));
+    return true;
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+  }
+
+  Token processCharacters(CharactersToken token) {
+    startTagHead(new StartTagToken("head", data: {}));
+    return token;
+  }
+
+  Token startTagHtml(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  void startTagHead(StartTagToken token) {
+    tree.insertElement(token);
+    tree.headPointer = tree.openElements.last;
+    parser.phase = parser._inHeadPhase;
+  }
+
+  Token startTagOther(StartTagToken token) {
+    startTagHead(new StartTagToken("head", data: {}));
+    return token;
+  }
+
+  Token endTagImplyHead(EndTagToken token) {
+    startTagHead(new StartTagToken("head", data: {}));
+    return token;
+  }
+
+  void endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "end-tag-after-implied-root",
+        {"name": token.name});
+  }
+}
+
+class InHeadPhase extends Phase {
+  InHeadPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "title": return startTagTitle(token);
+      case "noscript": case "noframes": case "style":
+        return startTagNoScriptNoFramesStyle(token);
+      case "script": return startTagScript(token);
+      case "base": case "basefont": case "bgsound": case "command": case "link":
+        return startTagBaseLinkCommand(token);
+      case "meta": return startTagMeta(token);
+      case "head": return startTagHead(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "head": return endTagHead(token);
+      case "br": case "html": case "body": return endTagHtmlBodyBr(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  // the real thing
+  bool processEOF() {
+    anythingElse();
+    return true;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    anythingElse();
+    return token;
+  }
+
+  Token startTagHtml(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  void startTagHead(StartTagToken token) {
+    parser.parseError(token.span, "two-heads-are-not-better-than-one");
+  }
+
+  void startTagBaseLinkCommand(StartTagToken token) {
+    tree.insertElement(token);
+    tree.openElements.removeLast();
+    token.selfClosingAcknowledged = true;
+  }
+
+  void startTagMeta(StartTagToken token) {
+    tree.insertElement(token);
+    tree.openElements.removeLast();
+    token.selfClosingAcknowledged = true;
+
+    var attributes = token.data;
+    if (!parser.tokenizer.stream.charEncodingCertain) {
+      var charset = attributes["charset"];
+      var content = attributes["content"];
+      if (charset != null) {
+        parser.tokenizer.stream.changeEncoding(charset);
+      } else if (content != null) {
+        var data = new EncodingBytes(content);
+        var codec = new ContentAttrParser(data).parse();
+        parser.tokenizer.stream.changeEncoding(codec);
+      }
+    }
+  }
+
+  void startTagTitle(StartTagToken token) {
+    parser.parseRCDataRawtext(token, "RCDATA");
+  }
+
+  void startTagNoScriptNoFramesStyle(StartTagToken token) {
+    // Need to decide whether to implement the scripting-disabled case
+    parser.parseRCDataRawtext(token, "RAWTEXT");
+  }
+
+  void startTagScript(StartTagToken token) {
+    tree.insertElement(token);
+    parser.tokenizer.state = parser.tokenizer.scriptDataState;
+    parser.originalPhase = parser.phase;
+    parser.phase = parser._textPhase;
+  }
+
+  Token startTagOther(StartTagToken token) {
+    anythingElse();
+    return token;
+  }
+
+  void endTagHead(EndTagToken token) {
+    var node = parser.tree.openElements.removeLast();
+    assert(node.tagName == "head");
+    parser.phase = parser._afterHeadPhase;
+  }
+
+  Token endTagHtmlBodyBr(EndTagToken token) {
+    anythingElse();
+    return token;
+  }
+
+  void endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+  }
+
+  void anythingElse() {
+    endTagHead(new EndTagToken("head"));
+  }
+}
+
+
+// XXX If we implement a parser for which scripting is disabled we need to
+// implement this phase.
+//
+// class InHeadNoScriptPhase extends Phase {
+
+class AfterHeadPhase extends Phase {
+  AfterHeadPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "body": return startTagBody(token);
+      case "frameset": return startTagFrameset(token);
+      case "base": case "basefont": case "bgsound": case "link": case "meta":
+      case "noframes": case "script": case "style": case "title":
+        return startTagFromHead(token);
+      case "head": return startTagHead(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "body": case "html": case "br":
+        return endTagHtmlBodyBr(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  bool processEOF() {
+    anythingElse();
+    return true;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    anythingElse();
+    return token;
+  }
+
+  Token startTagHtml(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  void startTagBody(StartTagToken token) {
+    parser.framesetOK = false;
+    tree.insertElement(token);
+    parser.phase = parser._inBodyPhase;
+  }
+
+  void startTagFrameset(StartTagToken token) {
+    tree.insertElement(token);
+    parser.phase = parser._inFramesetPhase;
+  }
+
+  void startTagFromHead(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-out-of-my-head",
+      {"name": token.name});
+    tree.openElements.add(tree.headPointer);
+    parser._inHeadPhase.processStartTag(token);
+    for (Node node in tree.openElements.reversed) {
+      if (node.tagName == "head") {
+        tree.openElements.remove(node);
+        break;
+      }
+    }
+  }
+
+  void startTagHead(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag", {"name": token.name});
+  }
+
+  Token startTagOther(StartTagToken token) {
+    anythingElse();
+    return token;
+  }
+
+  Token endTagHtmlBodyBr(EndTagToken token) {
+    anythingElse();
+    return token;
+  }
+
+  void endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+  }
+
+  void anythingElse() {
+    tree.insertElement(new StartTagToken("body", data: {}));
+    parser.phase = parser._inBodyPhase;
+    parser.framesetOK = true;
+  }
+}
+
+typedef Token TokenProccessor(Token token);
+
+class InBodyPhase extends Phase {
+  bool dropNewline = false;
+
+  // http://www.whatwg.org/specs/web-apps/current-work///parsing-main-inbody
+  // the really-really-really-very crazy mode
+  InBodyPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html":
+        return startTagHtml(token);
+      case "base": case "basefont": case "bgsound": case "command": case "link":
+      case "meta": case "noframes": case "script": case "style": case "title":
+        return startTagProcessInHead(token);
+      case "body":
+        return startTagBody(token);
+      case "frameset":
+        return startTagFrameset(token);
+      case "address": case "article": case "aside": case "blockquote":
+      case "center": case "details": case "details": case "dir": case "div":
+      case "dl": case "fieldset": case "figcaption": case "figure":
+      case "footer": case "header": case "hgroup": case "menu": case "nav":
+      case "ol": case "p": case "section": case "summary": case "ul":
+        return startTagCloseP(token);
+      // headingElements
+      case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
+        return startTagHeading(token);
+      case "pre": case "listing":
+        return startTagPreListing(token);
+      case "form":
+        return startTagForm(token);
+      case "li": case "dd": case "dt":
+        return startTagListItem(token);
+      case "plaintext":
+        return startTagPlaintext(token);
+      case "a": return startTagA(token);
+      case "b": case "big": case "code": case "em": case "font": case "i":
+      case "s": case "small": case "strike": case "strong": case "tt": case "u":
+        return startTagFormatting(token);
+      case "nobr":
+        return startTagNobr(token);
+      case "button":
+        return startTagButton(token);
+      case "applet": case "marquee": case "object":
+        return startTagAppletMarqueeObject(token);
+      case "xmp":
+        return startTagXmp(token);
+      case "table":
+        return startTagTable(token);
+      case "area": case "br": case "embed": case "img": case "keygen":
+      case "wbr":
+        return startTagVoidFormatting(token);
+      case "param": case "source": case "track":
+        return startTagParamSource(token);
+      case "input":
+        return startTagInput(token);
+      case "hr":
+        return startTagHr(token);
+      case "image":
+        return startTagImage(token);
+      case "isindex":
+        return startTagIsIndex(token);
+      case "textarea":
+        return startTagTextarea(token);
+      case "iframe":
+        return startTagIFrame(token);
+      case "noembed": case "noframes": case "noscript":
+        return startTagRawtext(token);
+      case "select":
+        return startTagSelect(token);
+      case "rp": case "rt":
+        return startTagRpRt(token);
+      case "option": case "optgroup":
+        return startTagOpt(token);
+      case "math":
+        return startTagMath(token);
+      case "svg":
+        return startTagSvg(token);
+      case "caption": case "col": case "colgroup": case "frame": case "head":
+      case "tbody": case "td": case "tfoot": case "th": case "thead": case "tr":
+        return startTagMisplaced(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "body": return endTagBody(token);
+      case "html": return endTagHtml(token);
+      case "address": case "article": case "aside": case "blockquote":
+      case "center": case "details": case "dir": case "div": case "dl":
+      case "fieldset": case "figcaption": case "figure": case "footer":
+      case "header": case "hgroup": case "listing": case "menu": case "nav":
+      case "ol": case "pre": case "section": case "summary": case "ul":
+        return endTagBlock(token);
+      case "form": return endTagForm(token);
+      case "p": return endTagP(token);
+      case "dd": case "dt": case "li": return endTagListItem(token);
+      // headingElements
+      case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
+        return endTagHeading(token);
+      case "a": case "b": case "big": case "code": case "em": case "font":
+      case "i": case "nobr": case "s": case "small": case "strike":
+      case "strong": case "tt": case "u":
+        return endTagFormatting(token);
+      case "applet": case "marquee": case "object":
+        return endTagAppletMarqueeObject(token);
+      case "br": return endTagBr(token);
+        default: return endTagOther(token);
+    }
+  }
+
+  bool isMatchingFormattingElement(Node node1, Node node2) {
+    if (node1.tagName != node2.tagName || node1.namespace != node2.namespace) {
+      return false;
+    } else if (node1.attributes.length != node2.attributes.length) {
+      return false;
+    } else {
+      for (var key in node1.attributes.keys) {
+        if (node1.attributes[key] != node2.attributes[key]) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  // helper
+  void addFormattingElement(token) {
+    tree.insertElement(token);
+    var element = tree.openElements.last;
+
+    var matchingElements = [];
+    for (Node node in tree.activeFormattingElements.reversed) {
+      if (node == Marker) {
+        break;
+      } else if (isMatchingFormattingElement(node, element)) {
+        matchingElements.add(node);
+      }
+    }
+
+    assert(matchingElements.length <= 3);
+    if (matchingElements.length == 3) {
+      tree.activeFormattingElements.remove(matchingElements.last);
+    }
+    tree.activeFormattingElements.add(element);
+  }
+
+  // the real deal
+  bool processEOF() {
+    for (Node node in tree.openElements.reversed) {
+      switch (node.tagName) {
+        case "dd": case "dt": case "li": case "p": case "tbody": case "td":
+        case "tfoot": case "th": case "thead": case "tr": case "body":
+        case "html":
+          continue;
+      }
+      parser.parseError(node.sourceSpan, "expected-closing-tag-but-got-eof");
+      break;
+    }
+    //Stop parsing
+    return false;
+  }
+
+  void processSpaceCharactersDropNewline(StringToken token) {
+    // Sometimes (start of <pre>, <listing>, and <textarea> blocks) we
+    // want to drop leading newlines
+    var data = token.data;
+    dropNewline = false;
+    if (data.startsWith("\n")) {
+      var lastOpen = tree.openElements.last;
+      if (const ["pre", "listing", "textarea"].contains(lastOpen.tagName)
+          && !lastOpen.hasContent()) {
+        data = data.substring(1);
+      }
+    }
+    if (data.length > 0) {
+      tree.reconstructActiveFormattingElements();
+      tree.insertText(data, token.span);
+    }
+  }
+
+  Token processCharacters(CharactersToken token) {
+    if (token.data == "\u0000") {
+      //The tokenizer should always emit null on its own
+      return null;
+    }
+    tree.reconstructActiveFormattingElements();
+    tree.insertText(token.data, token.span);
+    if (parser.framesetOK && !allWhitespace(token.data)) {
+      parser.framesetOK = false;
+    }
+    return null;
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    if (dropNewline) {
+      processSpaceCharactersDropNewline(token);
+    } else {
+      tree.reconstructActiveFormattingElements();
+      tree.insertText(token.data, token.span);
+    }
+    return null;
+  }
+
+  Token startTagProcessInHead(StartTagToken token) {
+    return parser._inHeadPhase.processStartTag(token);
+  }
+
+  void startTagBody(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag", {"name": "body"});
+    if (tree.openElements.length == 1
+        || tree.openElements[1].tagName != "body") {
+      assert(parser.innerHTMLMode);
+    } else {
+      parser.framesetOK = false;
+      token.data.forEach((attr, value) {
+        tree.openElements[1].attributes.putIfAbsent(attr, () => value);
+      });
+    }
+  }
+
+  void startTagFrameset(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag", {"name": "frameset"});
+    if ((tree.openElements.length == 1 ||
+        tree.openElements[1].tagName != "body")) {
+      assert(parser.innerHTMLMode);
+    } else if (parser.framesetOK) {
+      if (tree.openElements[1].parent != null) {
+        tree.openElements[1].parent.nodes.remove(tree.openElements[1]);
+      }
+      while (tree.openElements.last.tagName != "html") {
+        tree.openElements.removeLast();
+      }
+      tree.insertElement(token);
+      parser.phase = parser._inFramesetPhase;
+    }
+  }
+
+  void startTagCloseP(StartTagToken token) {
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(new EndTagToken("p"));
+    }
+    tree.insertElement(token);
+  }
+
+  void startTagPreListing(StartTagToken token) {
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(new EndTagToken("p"));
+    }
+    tree.insertElement(token);
+    parser.framesetOK = false;
+    dropNewline = true;
+  }
+
+  void startTagForm(StartTagToken token) {
+    if (tree.formPointer != null) {
+      parser.parseError(token.span, "unexpected-start-tag", {"name": "form"});
+    } else {
+      if (tree.elementInScope("p", variant: "button")) {
+        endTagP(new EndTagToken("p"));
+      }
+      tree.insertElement(token);
+      tree.formPointer = tree.openElements.last;
+    }
+  }
+
+  void startTagListItem(StartTagToken token) {
+    parser.framesetOK = false;
+
+    final stopNamesMap = const {"li": const ["li"],
+                                "dt": const ["dt", "dd"],
+                                "dd": const ["dt", "dd"]};
+    var stopNames = stopNamesMap[token.name];
+    for (Node node in tree.openElements.reversed) {
+      if (stopNames.contains(node.tagName)) {
+        parser.phase.processEndTag(new EndTagToken(node.tagName));
+        break;
+      }
+      if (specialElements.contains(node.nameTuple) &&
+          !const ["address", "div", "p"].contains(node.tagName)) {
+        break;
+      }
+    }
+
+    if (tree.elementInScope("p", variant: "button")) {
+      parser.phase.processEndTag(new EndTagToken("p"));
+    }
+
+    tree.insertElement(token);
+  }
+
+  void startTagPlaintext(StartTagToken token) {
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(new EndTagToken("p"));
+    }
+    tree.insertElement(token);
+    parser.tokenizer.state = parser.tokenizer.plaintextState;
+  }
+
+  void startTagHeading(StartTagToken token) {
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(new EndTagToken("p"));
+    }
+    if (headingElements.contains(tree.openElements.last.tagName)) {
+      parser.parseError(token.span, "unexpected-start-tag",
+          {"name": token.name});
+      tree.openElements.removeLast();
+    }
+    tree.insertElement(token);
+  }
+
+  void startTagA(StartTagToken token) {
+    var afeAElement = tree.elementInActiveFormattingElements("a");
+    if (afeAElement != null) {
+      parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+          {"startName": "a", "endName": "a"});
+      endTagFormatting(new EndTagToken("a"));
+      tree.openElements.remove(afeAElement);
+      tree.activeFormattingElements.remove(afeAElement);
+    }
+    tree.reconstructActiveFormattingElements();
+    addFormattingElement(token);
+  }
+
+  void startTagFormatting(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    addFormattingElement(token);
+  }
+
+  void startTagNobr(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    if (tree.elementInScope("nobr")) {
+      parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+        {"startName": "nobr", "endName": "nobr"});
+      processEndTag(new EndTagToken("nobr"));
+      // XXX Need tests that trigger the following
+      tree.reconstructActiveFormattingElements();
+    }
+    addFormattingElement(token);
+  }
+
+  Token startTagButton(StartTagToken token) {
+    if (tree.elementInScope("button")) {
+      parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+        {"startName": "button", "endName": "button"});
+      processEndTag(new EndTagToken("button"));
+      return token;
+    } else {
+      tree.reconstructActiveFormattingElements();
+      tree.insertElement(token);
+      parser.framesetOK = false;
+    }
+  }
+
+  void startTagAppletMarqueeObject(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    tree.insertElement(token);
+    tree.activeFormattingElements.add(Marker);
+    parser.framesetOK = false;
+  }
+
+  void startTagXmp(StartTagToken token) {
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(new EndTagToken("p"));
+    }
+    tree.reconstructActiveFormattingElements();
+    parser.framesetOK = false;
+    parser.parseRCDataRawtext(token, "RAWTEXT");
+  }
+
+  void startTagTable(StartTagToken token) {
+    if (parser.compatMode != "quirks") {
+      if (tree.elementInScope("p", variant: "button")) {
+        processEndTag(new EndTagToken("p"));
+      }
+    }
+    tree.insertElement(token);
+    parser.framesetOK = false;
+    parser.phase = parser._inTablePhase;
+  }
+
+  void startTagVoidFormatting(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    tree.insertElement(token);
+    tree.openElements.removeLast();
+    token.selfClosingAcknowledged = true;
+    parser.framesetOK = false;
+  }
+
+  void startTagInput(StartTagToken token) {
+    var savedFramesetOK = parser.framesetOK;
+    startTagVoidFormatting(token);
+    if (asciiUpper2Lower(token.data["type"]) == "hidden") {
+      //input type=hidden doesn't change framesetOK
+      parser.framesetOK = savedFramesetOK;
+    }
+  }
+
+  void startTagParamSource(StartTagToken token) {
+    tree.insertElement(token);
+    tree.openElements.removeLast();
+    token.selfClosingAcknowledged = true;
+  }
+
+  void startTagHr(StartTagToken token) {
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(new EndTagToken("p"));
+    }
+    tree.insertElement(token);
+    tree.openElements.removeLast();
+    token.selfClosingAcknowledged = true;
+    parser.framesetOK = false;
+  }
+
+  void startTagImage(StartTagToken token) {
+    // No really...
+    parser.parseError(token.span, "unexpected-start-tag-treated-as",
+        {"originalName": "image", "newName": "img"});
+    processStartTag(new StartTagToken("img", data: token.data,
+        selfClosing: token.selfClosing));
+  }
+
+  void startTagIsIndex(StartTagToken token) {
+    parser.parseError(token.span, "deprecated-tag", {"name": "isindex"});
+    if (tree.formPointer != null) {
+      return;
+    }
+    var formAttrs = {};
+    var dataAction = token.data["action"];
+    if (dataAction != null) {
+      formAttrs["action"] = dataAction;
+    }
+    processStartTag(new StartTagToken("form", data: formAttrs));
+    processStartTag(new StartTagToken("hr", data: {}));
+    processStartTag(new StartTagToken("label", data: {}));
+    // XXX Localization ...
+    var prompt = token.data["prompt"];
+    if (prompt == null) {
+      prompt = "This is a searchable index. Enter search keywords: ";
+    }
+    processCharacters(new CharactersToken(prompt));
+    var attributes = new LinkedHashMap.from(token.data);
+    attributes.remove('action');
+    attributes.remove('prompt');
+    attributes["name"] = "isindex";
+    processStartTag(new StartTagToken("input",
+                    data: attributes, selfClosing: token.selfClosing));
+    processEndTag(new EndTagToken("label"));
+    processStartTag(new StartTagToken("hr", data: {}));
+    processEndTag(new EndTagToken("form"));
+  }
+
+  void startTagTextarea(StartTagToken token) {
+    tree.insertElement(token);
+    parser.tokenizer.state = parser.tokenizer.rcdataState;
+    dropNewline = true;
+    parser.framesetOK = false;
+  }
+
+  void startTagIFrame(StartTagToken token) {
+    parser.framesetOK = false;
+    startTagRawtext(token);
+  }
+
+  /** iframe, noembed noframes, noscript(if scripting enabled). */
+  void startTagRawtext(StartTagToken token) {
+    parser.parseRCDataRawtext(token, "RAWTEXT");
+  }
+
+  void startTagOpt(StartTagToken token) {
+    if (tree.openElements.last.tagName == "option") {
+      parser.phase.processEndTag(new EndTagToken("option"));
+    }
+    tree.reconstructActiveFormattingElements();
+    parser.tree.insertElement(token);
+  }
+
+  void startTagSelect(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    tree.insertElement(token);
+    parser.framesetOK = false;
+
+    if (parser._inTablePhase == parser.phase ||
+        parser._inCaptionPhase == parser.phase ||
+        parser._inColumnGroupPhase == parser.phase ||
+        parser._inTableBodyPhase == parser.phase ||
+        parser._inRowPhase == parser.phase ||
+        parser._inCellPhase == parser.phase) {
+      parser.phase = parser._inSelectInTablePhase;
+    } else {
+      parser.phase = parser._inSelectPhase;
+    }
+  }
+
+  void startTagRpRt(StartTagToken token) {
+    if (tree.elementInScope("ruby")) {
+      tree.generateImpliedEndTags();
+      var last = tree.openElements.last;
+      if (last.tagName != "ruby") {
+        parser.parseError(last.sourceSpan, 'undefined-error');
+      }
+    }
+    tree.insertElement(token);
+  }
+
+  void startTagMath(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    parser.adjustMathMLAttributes(token);
+    parser.adjustForeignAttributes(token);
+    token.namespace = Namespaces.mathml;
+    tree.insertElement(token);
+    //Need to get the parse error right for the case where the token
+    //has a namespace not equal to the xmlns attribute
+    if (token.selfClosing) {
+      tree.openElements.removeLast();
+      token.selfClosingAcknowledged = true;
+    }
+  }
+
+  void startTagSvg(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    parser.adjustSVGAttributes(token);
+    parser.adjustForeignAttributes(token);
+    token.namespace = Namespaces.svg;
+    tree.insertElement(token);
+    //Need to get the parse error right for the case where the token
+    //has a namespace not equal to the xmlns attribute
+    if (token.selfClosing) {
+      tree.openElements.removeLast();
+      token.selfClosingAcknowledged = true;
+    }
+  }
+
+  /**
+   * Elements that should be children of other elements that have a
+   * different insertion mode; here they are ignored
+   * "caption", "col", "colgroup", "frame", "frameset", "head",
+   * "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
+   * "tr", "noscript"
+  */
+  void startTagMisplaced(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-ignored",
+        {"name": token.name});
+  }
+
+  Token startTagOther(StartTagToken token) {
+    tree.reconstructActiveFormattingElements();
+    tree.insertElement(token);
+  }
+
+  void endTagP(EndTagToken token) {
+    if (!tree.elementInScope("p", variant: "button")) {
+      startTagCloseP(new StartTagToken("p", data: {}));
+      parser.parseError(token.span, "unexpected-end-tag", {"name": "p"});
+      endTagP(new EndTagToken("p"));
+    } else {
+      tree.generateImpliedEndTags("p");
+      if (tree.openElements.last.tagName != "p") {
+        parser.parseError(token.span, "unexpected-end-tag", {"name": "p"});
+      }
+      popOpenElementsUntil("p");
+    }
+  }
+
+  void endTagBody(EndTagToken token) {
+    if (!tree.elementInScope("body")) {
+      parser.parseError(token.span, 'undefined-error');
+      return;
+    } else if (tree.openElements.last.tagName != "body") {
+      for (Node node in slice(tree.openElements, 2)) {
+        switch (node.tagName) {
+          case "dd": case "dt": case "li": case "optgroup": case "option":
+          case "p": case "rp": case "rt": case "tbody": case "td": case "tfoot":
+          case "th": case "thead": case "tr": case "body": case "html":
+            continue;
+        }
+        // Not sure this is the correct name for the parse error
+        parser.parseError(token.span, "expected-one-end-tag-but-got-another",
+            {"expectedName": "body", "gotName": node.tagName});
+        break;
+      }
+    }
+    parser.phase = parser._afterBodyPhase;
+  }
+
+  Token endTagHtml(EndTagToken token) {
+    //We repeat the test for the body end tag token being ignored here
+    if (tree.elementInScope("body")) {
+      endTagBody(new EndTagToken("body"));
+      return token;
+    }
+  }
+
+  void endTagBlock(EndTagToken token) {
+    //Put us back in the right whitespace handling mode
+    if (token.name == "pre") {
+      dropNewline = false;
+    }
+    var inScope = tree.elementInScope(token.name);
+    if (inScope) {
+      tree.generateImpliedEndTags();
+    }
+    if (tree.openElements.last.tagName != token.name) {
+      parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
+    }
+    if (inScope) {
+      popOpenElementsUntil(token.name);
+    }
+  }
+
+  void endTagForm(EndTagToken token) {
+    var node = tree.formPointer;
+    tree.formPointer = null;
+    if (node == null || !tree.elementInScope(node)) {
+      parser.parseError(token.span, "unexpected-end-tag", {"name": "form"});
+    } else {
+      tree.generateImpliedEndTags();
+      if (tree.openElements.last != node) {
+        parser.parseError(token.span, "end-tag-too-early-ignored", {"name": "form"});
+      }
+      tree.openElements.remove(node);
+    }
+  }
+
+  void endTagListItem(EndTagToken token) {
+    var variant;
+    if (token.name == "li") {
+      variant = "list";
+    } else {
+      variant = null;
+    }
+    if (!tree.elementInScope(token.name, variant: variant)) {
+      parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+    } else {
+      tree.generateImpliedEndTags(token.name);
+      if (tree.openElements.last.tagName != token.name) {
+        parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
+      }
+      popOpenElementsUntil(token.name);
+    }
+  }
+
+  void endTagHeading(EndTagToken token) {
+    for (var item in headingElements) {
+      if (tree.elementInScope(item)) {
+        tree.generateImpliedEndTags();
+        break;
+      }
+    }
+    if (tree.openElements.last.tagName != token.name) {
+      parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
+    }
+
+    for (var item in headingElements) {
+      if (tree.elementInScope(item)) {
+        item = tree.openElements.removeLast();
+        while (!headingElements.contains(item.tagName)) {
+          item = tree.openElements.removeLast();
+        }
+        break;
+      }
+    }
+  }
+
+  /** The much-feared adoption agency algorithm. */
+  endTagFormatting(EndTagToken token) {
+    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adoptionAgency
+    // TODO(jmesserly): the comments here don't match the numbered steps in the
+    // updated spec. This needs a pass over it to verify that it still matches.
+    // In particular the html5lib Python code skiped "step 4", I'm not sure why.
+    // XXX Better parseError messages appreciated.
+    int outerLoopCounter = 0;
+    while (outerLoopCounter < 8) {
+      outerLoopCounter += 1;
+
+      // Step 1 paragraph 1
+      var formattingElement = tree.elementInActiveFormattingElements(
+          token.name);
+      if (formattingElement == null ||
+          (tree.openElements.contains(formattingElement) &&
+           !tree.elementInScope(formattingElement.tagName))) {
+        parser.parseError(token.span, "adoption-agency-1.1",
+            {"name": token.name});
+        return;
+      // Step 1 paragraph 2
+      } else if (!tree.openElements.contains(formattingElement)) {
+        parser.parseError(token.span, "adoption-agency-1.2",
+            {"name": token.name});
+        tree.activeFormattingElements.remove(formattingElement);
+        return;
+      }
+
+      // Step 1 paragraph 3
+      if (formattingElement != tree.openElements.last) {
+        parser.parseError(token.span, "adoption-agency-1.3",
+            {"name": token.name});
+      }
+
+      // Step 2
+      // Start of the adoption agency algorithm proper
+      var afeIndex = tree.openElements.indexOf(formattingElement);
+      Node furthestBlock = null;
+      for (Node element in slice(tree.openElements, afeIndex)) {
+        if (specialElements.contains(element.nameTuple)) {
+          furthestBlock = element;
+          break;
+        }
+      }
+      // Step 3
+      if (furthestBlock == null) {
+        var element = tree.openElements.removeLast();
+        while (element != formattingElement) {
+          element = tree.openElements.removeLast();
+        }
+        tree.activeFormattingElements.remove(element);
+        return;
+      }
+
+      var commonAncestor = tree.openElements[afeIndex - 1];
+
+      // Step 5
+      // The bookmark is supposed to help us identify where to reinsert
+      // nodes in step 12. We have to ensure that we reinsert nodes after
+      // the node before the active formatting element. Note the bookmark
+      // can move in step 7.4
+      var bookmark = tree.activeFormattingElements.indexOf(formattingElement);
+
+      // Step 6
+      Node lastNode = furthestBlock;
+      var node = furthestBlock;
+      int innerLoopCounter = 0;
+
+      var index = tree.openElements.indexOf(node);
+      while (innerLoopCounter < 3) {
+        innerLoopCounter += 1;
+
+        // Node is element before node in open elements
+        index -= 1;
+        node = tree.openElements[index];
+        if (!tree.activeFormattingElements.contains(node)) {
+          tree.openElements.remove(node);
+          continue;
+        }
+        // Step 6.3
+        if (node == formattingElement) {
+          break;
+        }
+        // Step 6.4
+        if (lastNode == furthestBlock) {
+          bookmark = (tree.activeFormattingElements.indexOf(node) + 1);
+        }
+        // Step 6.5
+        //cite = node.parent
+        var clone = node.clone();
+        // Replace node with clone
+        tree.activeFormattingElements[
+            tree.activeFormattingElements.indexOf(node)] = clone;
+        tree.openElements[tree.openElements.indexOf(node)] = clone;
+        node = clone;
+
+        // Step 6.6
+        // Remove lastNode from its parents, if any
+        if (lastNode.parent != null) {
+          lastNode.parent.nodes.remove(lastNode);
+        }
+        node.nodes.add(lastNode);
+        // Step 7.7
+        lastNode = node;
+        // End of inner loop
+      }
+
+      // Step 7
+      // Foster parent lastNode if commonAncestor is a
+      // table, tbody, tfoot, thead, or tr we need to foster parent the
+      // lastNode
+      if (lastNode.parent != null) {
+        lastNode.parent.nodes.remove(lastNode);
+      }
+
+      if (const ["table", "tbody", "tfoot", "thead", "tr"].contains(
+          commonAncestor.tagName)) {
+        var nodePos = tree.getTableMisnestedNodePosition();
+        nodePos[0].insertBefore(lastNode, nodePos[1]);
+      } else {
+        commonAncestor.nodes.add(lastNode);
+      }
+
+      // Step 8
+      var clone = formattingElement.clone();
+
+      // Step 9
+      furthestBlock.reparentChildren(clone);
+
+      // Step 10
+      furthestBlock.nodes.add(clone);
+
+      // Step 11
+      tree.activeFormattingElements.remove(formattingElement);
+      tree.activeFormattingElements.insert(
+          min(bookmark, tree.activeFormattingElements.length), clone);
+
+      // Step 12
+      tree.openElements.remove(formattingElement);
+      tree.openElements.insert(
+          tree.openElements.indexOf(furthestBlock) + 1, clone);
+    }
+  }
+
+  void endTagAppletMarqueeObject(EndTagToken token) {
+    if (tree.elementInScope(token.name)) {
+      tree.generateImpliedEndTags();
+    }
+    if (tree.openElements.last.tagName != token.name) {
+      parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
+    }
+    if (tree.elementInScope(token.name)) {
+      popOpenElementsUntil(token.name);
+      tree.clearActiveFormattingElements();
+    }
+  }
+
+  void endTagBr(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-treated-as",
+        {"originalName": "br", "newName": "br element"});
+    tree.reconstructActiveFormattingElements();
+    tree.insertElement(new StartTagToken("br", data: {}));
+    tree.openElements.removeLast();
+  }
+
+  void endTagOther(EndTagToken token) {
+    for (Node node in tree.openElements.reversed) {
+      if (node.tagName == token.name) {
+        tree.generateImpliedEndTags(token.name);
+        if (tree.openElements.last.tagName != token.name) {
+          parser.parseError(token.span, "unexpected-end-tag",
+              {"name": token.name});
+        }
+        while (tree.openElements.removeLast() != node);
+        break;
+      } else {
+        if (specialElements.contains(node.nameTuple)) {
+          parser.parseError(token.span, "unexpected-end-tag",
+              {"name": token.name});
+          break;
+        }
+      }
+    }
+  }
+}
+
+
+class TextPhase extends Phase {
+  TextPhase(parser) : super(parser);
+
+  // "Tried to process start tag %s in RCDATA/RAWTEXT mode"%token.name
+  processStartTag(StartTagToken token) { assert(false); }
+
+  processEndTag(EndTagToken token) {
+    if (token.name == 'script') return endTagScript(token);
+    return endTagOther(token);
+  }
+
+  Token processCharacters(CharactersToken token) {
+    tree.insertText(token.data, token.span);
+  }
+
+  bool processEOF() {
+    var last = tree.openElements.last;
+    parser.parseError(last.sourceSpan, "expected-named-closing-tag-but-got-eof",
+        {'name': last.tagName});
+    tree.openElements.removeLast();
+    parser.phase = parser.originalPhase;
+    return true;
+  }
+
+  void endTagScript(EndTagToken token) {
+    var node = tree.openElements.removeLast();
+    assert(node.tagName == "script");
+    parser.phase = parser.originalPhase;
+    //The rest of this method is all stuff that only happens if
+    //document.write works
+  }
+
+  void endTagOther(EndTagToken token) {
+    var node = tree.openElements.removeLast();
+    parser.phase = parser.originalPhase;
+  }
+}
+
+class InTablePhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///in-table
+  InTablePhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "caption": return startTagCaption(token);
+      case "colgroup": return startTagColgroup(token);
+      case "col": return startTagCol(token);
+      case "tbody": case "tfoot": case "thead": return startTagRowGroup(token);
+      case "td": case "th": case "tr": return startTagImplyTbody(token);
+      case "table": return startTagTable(token);
+      case "style": case "script": return startTagStyleScript(token);
+      case "input": return startTagInput(token);
+      case "form": return startTagForm(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "table": return endTagTable(token);
+      case "body": case "caption": case "col": case "colgroup": case "html":
+      case "tbody": case "td": case "tfoot": case "th": case "thead": case "tr":
+        return endTagIgnore(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  // helper methods
+  void clearStackToTableContext() {
+    // "clear the stack back to a table context"
+    while (tree.openElements.last.tagName != "table" &&
+           tree.openElements.last.tagName != "html") {
+      //parser.parseError(token.span, "unexpected-implied-end-tag-in-table",
+      //  {"name":  tree.openElements.last.name})
+      tree.openElements.removeLast();
+    }
+    // When the current node is <html> it's an innerHTML case
+  }
+
+  // processing methods
+  bool processEOF() {
+    var last = tree.openElements.last;
+    if (last.tagName != "html") {
+      parser.parseError(last.sourceSpan, "eof-in-table");
+    } else {
+      assert(parser.innerHTMLMode);
+    }
+    //Stop parsing
+    return false;
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    var originalPhase = parser.phase;
+    parser.phase = parser._inTableTextPhase;
+    parser._inTableTextPhase.originalPhase = originalPhase;
+    parser.phase.processSpaceCharacters(token);
+  }
+
+  Token processCharacters(CharactersToken token) {
+    var originalPhase = parser.phase;
+    parser.phase = parser._inTableTextPhase;
+    parser._inTableTextPhase.originalPhase = originalPhase;
+    parser.phase.processCharacters(token);
+  }
+
+  void insertText(CharactersToken token) {
+    // If we get here there must be at least one non-whitespace character
+    // Do the table magic!
+    tree.insertFromTable = true;
+    parser._inBodyPhase.processCharacters(token);
+    tree.insertFromTable = false;
+  }
+
+  void startTagCaption(StartTagToken token) {
+    clearStackToTableContext();
+    tree.activeFormattingElements.add(Marker);
+    tree.insertElement(token);
+    parser.phase = parser._inCaptionPhase;
+  }
+
+  void startTagColgroup(StartTagToken token) {
+    clearStackToTableContext();
+    tree.insertElement(token);
+    parser.phase = parser._inColumnGroupPhase;
+  }
+
+  Token startTagCol(StartTagToken token) {
+    startTagColgroup(new StartTagToken("colgroup", data: {}));
+    return token;
+  }
+
+  void startTagRowGroup(StartTagToken token) {
+    clearStackToTableContext();
+    tree.insertElement(token);
+    parser.phase = parser._inTableBodyPhase;
+  }
+
+  Token startTagImplyTbody(StartTagToken token) {
+    startTagRowGroup(new StartTagToken("tbody", data: {}));
+    return token;
+  }
+
+  Token startTagTable(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+        {"startName": "table", "endName": "table"});
+    parser.phase.processEndTag(new EndTagToken("table"));
+    if (!parser.innerHTMLMode) {
+      return token;
+    }
+  }
+
+  Token startTagStyleScript(StartTagToken token) {
+    return parser._inHeadPhase.processStartTag(token);
+  }
+
+  void startTagInput(StartTagToken token) {
+    if (asciiUpper2Lower(token.data["type"]) == "hidden") {
+      parser.parseError(token.span, "unexpected-hidden-input-in-table");
+      tree.insertElement(token);
+      // XXX associate with form
+      tree.openElements.removeLast();
+    } else {
+      startTagOther(token);
+    }
+  }
+
+  void startTagForm(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-form-in-table");
+    if (tree.formPointer == null) {
+      tree.insertElement(token);
+      tree.formPointer = tree.openElements.last;
+      tree.openElements.removeLast();
+    }
+  }
+
+  void startTagOther(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-implies-table-voodoo",
+        {"name": token.name});
+    // Do the table magic!
+    tree.insertFromTable = true;
+    parser._inBodyPhase.processStartTag(token);
+    tree.insertFromTable = false;
+  }
+
+  void endTagTable(EndTagToken token) {
+    if (tree.elementInScope("table", variant: "table")) {
+      tree.generateImpliedEndTags();
+      var last = tree.openElements.last;
+      if (last.tagName != "table") {
+        parser.parseError(token.span, "end-tag-too-early-named",
+            {"gotName": "table", "expectedName": last.tagName});
+      }
+      while (tree.openElements.last.tagName != "table") {
+        tree.openElements.removeLast();
+      }
+      tree.openElements.removeLast();
+      parser.resetInsertionMode();
+    } else {
+      // innerHTML case
+      assert(parser.innerHTMLMode);
+      parser.parseError(token.span, "undefined-error");
+    }
+  }
+
+  void endTagIgnore(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+  }
+
+  void endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-implies-table-voodoo",
+        {"name": token.name});
+    // Do the table magic!
+    tree.insertFromTable = true;
+    parser._inBodyPhase.processEndTag(token);
+    tree.insertFromTable = false;
+  }
+}
+
+class InTableTextPhase extends Phase {
+  Phase originalPhase;
+  List<StringToken> characterTokens;
+
+  InTableTextPhase(parser)
+      : characterTokens = <StringToken>[],
+        super(parser);
+
+  void flushCharacters() {
+    if (characterTokens.length == 0) return;
+
+    // TODO(sigmund,jmesserly): remove '' (dartbug.com/8480)
+    var data = characterTokens.map((t) => t.data).join('');
+    var span = null;
+
+    if (parser.generateSpans) {
+      span = new FileSpan.union(
+          characterTokens[0].span,
+          characterTokens.last.span);
+    }
+
+    if (!allWhitespace(data)) {
+      parser._inTablePhase.insertText(new CharactersToken(data)..span = span);
+    } else if (data.length > 0) {
+      tree.insertText(data, span);
+    }
+    characterTokens = <StringToken>[];
+  }
+
+  Token processComment(CommentToken token) {
+    flushCharacters();
+    parser.phase = originalPhase;
+    return token;
+  }
+
+  bool processEOF() {
+    flushCharacters();
+    parser.phase = originalPhase;
+    return true;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    if (token.data == "\u0000") {
+      return null;
+    }
+    characterTokens.add(token);
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    //pretty sure we should never reach here
+    characterTokens.add(token);
+    // XXX assert(false);
+  }
+
+  Token processStartTag(StartTagToken token) {
+    flushCharacters();
+    parser.phase = originalPhase;
+    return token;
+  }
+
+  Token processEndTag(EndTagToken token) {
+    flushCharacters();
+    parser.phase = originalPhase;
+    return token;
+  }
+}
+
+
+class InCaptionPhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///in-caption
+  InCaptionPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "caption": case "col": case "colgroup": case "tbody": case "td":
+      case "tfoot": case "th": case "thead": case "tr":
+        return startTagTableElement(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "caption": return endTagCaption(token);
+      case "table": return endTagTable(token);
+      case "body": case "col": case "colgroup": case "html": case "tbody":
+      case "td": case "tfoot": case "th": case "thead": case "tr":
+        return endTagIgnore(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  bool ignoreEndTagCaption() {
+    return !tree.elementInScope("caption", variant: "table");
+  }
+
+  bool processEOF() {
+    parser._inBodyPhase.processEOF();
+    return false;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    return parser._inBodyPhase.processCharacters(token);
+  }
+
+  Token startTagTableElement(StartTagToken token) {
+    parser.parseError(token.span, "undefined-error");
+    //XXX Have to duplicate logic here to find out if the tag is ignored
+    var ignoreEndTag = ignoreEndTagCaption();
+    parser.phase.processEndTag(new EndTagToken("caption"));
+    if (!ignoreEndTag) {
+      return token;
+    }
+    return null;
+  }
+
+  Token startTagOther(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  void endTagCaption(EndTagToken token) {
+    if (!ignoreEndTagCaption()) {
+      // AT this code is quite similar to endTagTable in "InTable"
+      tree.generateImpliedEndTags();
+      if (tree.openElements.last.tagName != "caption") {
+        parser.parseError(token.span, "expected-one-end-tag-but-got-another",
+          {"gotName": "caption",
+           "expectedName": tree.openElements.last.tagName});
+      }
+      while (tree.openElements.last.tagName != "caption") {
+        tree.openElements.removeLast();
+      }
+      tree.openElements.removeLast();
+      tree.clearActiveFormattingElements();
+      parser.phase = parser._inTablePhase;
+    } else {
+      // innerHTML case
+      assert(parser.innerHTMLMode);
+      parser.parseError(token.span, "undefined-error");
+    }
+  }
+
+  Token endTagTable(EndTagToken token) {
+    parser.parseError(token.span, "undefined-error");
+    var ignoreEndTag = ignoreEndTagCaption();
+    parser.phase.processEndTag(new EndTagToken("caption"));
+    if (!ignoreEndTag) {
+      return token;
+    }
+    return null;
+  }
+
+  void endTagIgnore(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+  }
+
+  Token endTagOther(EndTagToken token) {
+    return parser._inBodyPhase.processEndTag(token);
+  }
+}
+
+
+class InColumnGroupPhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///in-column
+  InColumnGroupPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "col": return startTagCol(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "colgroup": return endTagColgroup(token);
+      case "col": return endTagCol(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  bool ignoreEndTagColgroup() {
+    return tree.openElements.last.tagName == "html";
+  }
+
+  bool processEOF() {
+    var ignoreEndTag = ignoreEndTagColgroup();
+    if (ignoreEndTag) {
+      assert(parser.innerHTMLMode);
+      return false;
+    } else {
+      endTagColgroup(new EndTagToken("colgroup"));
+      return true;
+    }
+  }
+
+  Token processCharacters(CharactersToken token) {
+    var ignoreEndTag = ignoreEndTagColgroup();
+    endTagColgroup(new EndTagToken("colgroup"));
+    return ignoreEndTag ? null : token;
+  }
+
+  void startTagCol(StartTagToken token) {
+    tree.insertElement(token);
+    tree.openElements.removeLast();
+  }
+
+  Token startTagOther(StartTagToken token) {
+    var ignoreEndTag = ignoreEndTagColgroup();
+    endTagColgroup(new EndTagToken("colgroup"));
+    return ignoreEndTag ? null : token;
+  }
+
+  void endTagColgroup(EndTagToken token) {
+    if (ignoreEndTagColgroup()) {
+      // innerHTML case
+      assert(parser.innerHTMLMode);
+      parser.parseError(token.span, "undefined-error");
+    } else {
+      tree.openElements.removeLast();
+      parser.phase = parser._inTablePhase;
+    }
+  }
+
+  void endTagCol(EndTagToken token) {
+    parser.parseError(token.span, "no-end-tag", {"name": "col"});
+  }
+
+  Token endTagOther(EndTagToken token) {
+    var ignoreEndTag = ignoreEndTagColgroup();
+    endTagColgroup(new EndTagToken("colgroup"));
+    return ignoreEndTag ? null : token;
+  }
+}
+
+
+class InTableBodyPhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///in-table0
+  InTableBodyPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "tr": return startTagTr(token);
+      case "td": case "th": return startTagTableCell(token);
+      case "caption": case "col": case "colgroup": case "tbody": case "tfoot":
+      case "thead":
+        return startTagTableOther(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "tbody": case "tfoot": case "thead":
+        return endTagTableRowGroup(token);
+      case "table": return endTagTable(token);
+      case "body": case "caption": case "col": case "colgroup": case "html":
+      case "td": case "th": case "tr":
+        return endTagIgnore(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  // helper methods
+  void clearStackToTableBodyContext() {
+    var tableTags = const ["tbody", "tfoot", "thead", "html"];
+    while (!tableTags.contains(tree.openElements.last.tagName)) {
+      //XXX parser.parseError(token.span, "unexpected-implied-end-tag-in-table",
+      //  {"name": tree.openElements.last.name})
+      tree.openElements.removeLast();
+    }
+    if (tree.openElements.last.tagName == "html") {
+      assert(parser.innerHTMLMode);
+    }
+  }
+
+  // the rest
+  bool processEOF() {
+    parser._inTablePhase.processEOF();
+    return false;
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    return parser._inTablePhase.processSpaceCharacters(token);
+  }
+
+  Token processCharacters(CharactersToken token) {
+    return parser._inTablePhase.processCharacters(token);
+  }
+
+  void startTagTr(StartTagToken token) {
+    clearStackToTableBodyContext();
+    tree.insertElement(token);
+    parser.phase = parser._inRowPhase;
+  }
+
+  Token startTagTableCell(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-cell-in-table-body",
+        {"name": token.name});
+    startTagTr(new StartTagToken("tr", data: {}));
+    return token;
+  }
+
+  Token startTagTableOther(token) => endTagTable(token);
+
+  Token startTagOther(StartTagToken token) {
+    return parser._inTablePhase.processStartTag(token);
+  }
+
+  void endTagTableRowGroup(EndTagToken token) {
+    if (tree.elementInScope(token.name, variant: "table")) {
+      clearStackToTableBodyContext();
+      tree.openElements.removeLast();
+      parser.phase = parser._inTablePhase;
+    } else {
+      parser.parseError(token.span, "unexpected-end-tag-in-table-body",
+          {"name": token.name});
+    }
+  }
+
+  Token endTagTable(TagToken token) {
+    // XXX AT Any ideas on how to share this with endTagTable?
+    if (tree.elementInScope("tbody", variant: "table") ||
+        tree.elementInScope("thead", variant: "table") ||
+        tree.elementInScope("tfoot", variant: "table")) {
+      clearStackToTableBodyContext();
+      endTagTableRowGroup(new EndTagToken(tree.openElements.last.tagName));
+      return token;
+    } else {
+      // innerHTML case
+      assert(parser.innerHTMLMode);
+      parser.parseError(token.span, "undefined-error");
+    }
+    return null;
+  }
+
+  void endTagIgnore(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-in-table-body",
+        {"name": token.name});
+  }
+
+  Token endTagOther(EndTagToken token) {
+    return parser._inTablePhase.processEndTag(token);
+  }
+}
+
+
+class InRowPhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///in-row
+  InRowPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "td": case "th": return startTagTableCell(token);
+      case "caption": case "col": case "colgroup": case "tbody": case "tfoot":
+      case "thead": case "tr":
+        return startTagTableOther(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "tr": return endTagTr(token);
+      case "table": return endTagTable(token);
+      case "tbody": case "tfoot": case "thead":
+        return endTagTableRowGroup(token);
+      case "body": case "caption": case "col": case "colgroup": case "html":
+      case "td": case "th":
+        return endTagIgnore(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  // helper methods (XXX unify this with other table helper methods)
+  void clearStackToTableRowContext() {
+    while (true) {
+      var last = tree.openElements.last;
+      if (last.tagName == "tr" || last.tagName == "html") break;
+
+      parser.parseError(last.sourceSpan,
+          "unexpected-implied-end-tag-in-table-row",
+          {"name": tree.openElements.last.tagName});
+      tree.openElements.removeLast();
+    }
+  }
+
+  bool ignoreEndTagTr() {
+    return !tree.elementInScope("tr", variant: "table");
+  }
+
+  // the rest
+  bool processEOF() {
+    parser._inTablePhase.processEOF();
+    return false;
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    return parser._inTablePhase.processSpaceCharacters(token);
+  }
+
+  Token processCharacters(CharactersToken token) {
+    return parser._inTablePhase.processCharacters(token);
+  }
+
+  void startTagTableCell(StartTagToken token) {
+    clearStackToTableRowContext();
+    tree.insertElement(token);
+    parser.phase = parser._inCellPhase;
+    tree.activeFormattingElements.add(Marker);
+  }
+
+  Token startTagTableOther(StartTagToken token) {
+    bool ignoreEndTag = ignoreEndTagTr();
+    endTagTr(new EndTagToken("tr"));
+    // XXX how are we sure it's always ignored in the innerHTML case?
+    return ignoreEndTag ? null : token;
+  }
+
+  Token startTagOther(StartTagToken token) {
+    return parser._inTablePhase.processStartTag(token);
+  }
+
+  void endTagTr(EndTagToken token) {
+    if (!ignoreEndTagTr()) {
+      clearStackToTableRowContext();
+      tree.openElements.removeLast();
+      parser.phase = parser._inTableBodyPhase;
+    } else {
+      // innerHTML case
+      assert(parser.innerHTMLMode);
+      parser.parseError(token.span, "undefined-error");
+    }
+  }
+
+  Token endTagTable(EndTagToken token) {
+    var ignoreEndTag = ignoreEndTagTr();
+    endTagTr(new EndTagToken("tr"));
+    // Reprocess the current tag if the tr end tag was not ignored
+    // XXX how are we sure it's always ignored in the innerHTML case?
+    return ignoreEndTag ? null : token;
+  }
+
+  Token endTagTableRowGroup(EndTagToken token) {
+    if (tree.elementInScope(token.name, variant: "table")) {
+      endTagTr(new EndTagToken("tr"));
+      return token;
+    } else {
+      parser.parseError(token.span, "undefined-error");
+      return null;
+    }
+  }
+
+  void endTagIgnore(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-in-table-row",
+        {"name": token.name});
+  }
+
+  Token endTagOther(EndTagToken token) {
+    return parser._inTablePhase.processEndTag(token);
+  }
+}
+
+class InCellPhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///in-cell
+  InCellPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "caption": case "col": case "colgroup": case "tbody": case "td":
+      case "tfoot": case "th": case "thead": case "tr":
+        return startTagTableOther(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "td": case "th":
+        return endTagTableCell(token);
+      case "body": case "caption": case "col": case "colgroup": case "html":
+        return endTagIgnore(token);
+      case "table": case "tbody": case "tfoot": case "thead": case "tr":
+        return endTagImply(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  // helper
+  void closeCell() {
+    if (tree.elementInScope("td", variant: "table")) {
+      endTagTableCell(new EndTagToken("td"));
+    } else if (tree.elementInScope("th", variant: "table")) {
+      endTagTableCell(new EndTagToken("th"));
+    }
+  }
+
+  // the rest
+  bool processEOF() {
+    parser._inBodyPhase.processEOF();
+    return false;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    return parser._inBodyPhase.processCharacters(token);
+  }
+
+  Token startTagTableOther(StartTagToken token) {
+    if (tree.elementInScope("td", variant: "table") ||
+      tree.elementInScope("th", variant: "table")) {
+      closeCell();
+      return token;
+    } else {
+      // innerHTML case
+      assert(parser.innerHTMLMode);
+      parser.parseError(token.span, "undefined-error");
+    }
+  }
+
+  Token startTagOther(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  void endTagTableCell(EndTagToken token) {
+    if (tree.elementInScope(token.name, variant: "table")) {
+      tree.generateImpliedEndTags(token.name);
+      if (tree.openElements.last.tagName != token.name) {
+        parser.parseError(token.span, "unexpected-cell-end-tag",
+            {"name": token.name});
+        popOpenElementsUntil(token.name);
+      } else {
+        tree.openElements.removeLast();
+      }
+      tree.clearActiveFormattingElements();
+      parser.phase = parser._inRowPhase;
+    } else {
+      parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+    }
+  }
+
+  void endTagIgnore(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+  }
+
+  Token endTagImply(EndTagToken token) {
+    if (tree.elementInScope(token.name, variant: "table")) {
+      closeCell();
+      return token;
+    } else {
+      // sometimes innerHTML case
+      parser.parseError(token.span, "undefined-error");
+    }
+  }
+
+  Token endTagOther(EndTagToken token) {
+    return parser._inBodyPhase.processEndTag(token);
+  }
+}
+
+class InSelectPhase extends Phase {
+  InSelectPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "option": return startTagOption(token);
+      case "optgroup": return startTagOptgroup(token);
+      case "select": return startTagSelect(token);
+      case "input": case "keygen": case "textarea":
+        return startTagInput(token);
+      case "script": return startTagScript(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "option": return endTagOption(token);
+      case "optgroup": return endTagOptgroup(token);
+      case "select": return endTagSelect(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  // http://www.whatwg.org/specs/web-apps/current-work///in-select
+  bool processEOF() {
+    var last = tree.openElements.last;
+    if (last.tagName != "html") {
+      parser.parseError(last.sourceSpan, "eof-in-select");
+    } else {
+      assert(parser.innerHTMLMode);
+    }
+    return false;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    if (token.data == "\u0000") {
+      return null;
+    }
+    tree.insertText(token.data, token.span);
+  }
+
+  void startTagOption(StartTagToken token) {
+    // We need to imply </option> if <option> is the current node.
+    if (tree.openElements.last.tagName == "option") {
+      tree.openElements.removeLast();
+    }
+    tree.insertElement(token);
+  }
+
+  void startTagOptgroup(StartTagToken token) {
+    if (tree.openElements.last.tagName == "option") {
+      tree.openElements.removeLast();
+    }
+    if (tree.openElements.last.tagName == "optgroup") {
+      tree.openElements.removeLast();
+    }
+    tree.insertElement(token);
+  }
+
+  void startTagSelect(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-select-in-select");
+    endTagSelect(new EndTagToken("select"));
+  }
+
+  Token startTagInput(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-input-in-select");
+    if (tree.elementInScope("select", variant: "select")) {
+      endTagSelect(new EndTagToken("select"));
+      return token;
+    } else {
+      assert(parser.innerHTMLMode);
+    }
+  }
+
+  Token startTagScript(StartTagToken token) {
+    return parser._inHeadPhase.processStartTag(token);
+  }
+
+  Token startTagOther(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-in-select",
+        {"name": token.name});
+  }
+
+  void endTagOption(EndTagToken token) {
+    if (tree.openElements.last.tagName == "option") {
+      tree.openElements.removeLast();
+    } else {
+      parser.parseError(token.span, "unexpected-end-tag-in-select",
+          {"name": "option"});
+    }
+  }
+
+  void endTagOptgroup(EndTagToken token) {
+    // </optgroup> implicitly closes <option>
+    if (tree.openElements.last.tagName == "option" &&
+      tree.openElements[tree.openElements.length - 2].tagName == "optgroup") {
+      tree.openElements.removeLast();
+    }
+    // It also closes </optgroup>
+    if (tree.openElements.last.tagName == "optgroup") {
+      tree.openElements.removeLast();
+    // But nothing else
+    } else {
+      parser.parseError(token.span, "unexpected-end-tag-in-select",
+        {"name": "optgroup"});
+    }
+  }
+
+  void endTagSelect(EndTagToken token) {
+    if (tree.elementInScope("select", variant: "select")) {
+      popOpenElementsUntil("select");
+      parser.resetInsertionMode();
+    } else {
+      // innerHTML case
+      assert(parser.innerHTMLMode);
+      parser.parseError(token.span, "undefined-error");
+    }
+  }
+
+  void endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-in-select",
+        {"name": token.name});
+  }
+}
+
+
+class InSelectInTablePhase extends Phase {
+  InSelectInTablePhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "caption": case "table": case "tbody": case "tfoot": case "thead":
+      case "tr": case "td": case "th":
+        return startTagTable(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "caption": case "table": case "tbody": case "tfoot": case "thead":
+      case "tr": case "td": case "th":
+        return endTagTable(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  bool processEOF() {
+    parser._inSelectPhase.processEOF();
+    return false;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    return parser._inSelectPhase.processCharacters(token);
+  }
+
+  Token startTagTable(StartTagToken token) {
+    parser.parseError(token.span,
+        "unexpected-table-element-start-tag-in-select-in-table",
+        {"name": token.name});
+    endTagOther(new EndTagToken("select"));
+    return token;
+  }
+
+  Token startTagOther(StartTagToken token) {
+    return parser._inSelectPhase.processStartTag(token);
+  }
+
+  Token endTagTable(EndTagToken token) {
+    parser.parseError(token.span,
+        "unexpected-table-element-end-tag-in-select-in-table",
+        {"name": token.name});
+    if (tree.elementInScope(token.name, variant: "table")) {
+      endTagOther(new EndTagToken("select"));
+      return token;
+    }
+  }
+
+  Token endTagOther(EndTagToken token) {
+    return parser._inSelectPhase.processEndTag(token);
+  }
+}
+
+
+class InForeignContentPhase extends Phase {
+  // TODO(jmesserly): this is sorted so we could binary search.
+  static const breakoutElements = const [
+    'b', 'big', 'blockquote', 'body', 'br','center', 'code', 'dd', 'div', 'dl',
+    'dt', 'em', 'embed', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'i',
+    'img', 'li', 'listing', 'menu', 'meta', 'nobr', 'ol', 'p', 'pre', 'ruby',
+    's', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tt', 'u',
+    'ul', 'var'
+  ];
+
+  InForeignContentPhase(parser) : super(parser);
+
+  void adjustSVGTagNames(token) {
+    final replacements = const {
+      "altglyph":"altGlyph",
+      "altglyphdef":"altGlyphDef",
+      "altglyphitem":"altGlyphItem",
+      "animatecolor":"animateColor",
+      "animatemotion":"animateMotion",
+      "animatetransform":"animateTransform",
+      "clippath":"clipPath",
+      "feblend":"feBlend",
+      "fecolormatrix":"feColorMatrix",
+      "fecomponenttransfer":"feComponentTransfer",
+      "fecomposite":"feComposite",
+      "feconvolvematrix":"feConvolveMatrix",
+      "fediffuselighting":"feDiffuseLighting",
+      "fedisplacementmap":"feDisplacementMap",
+      "fedistantlight":"feDistantLight",
+      "feflood":"feFlood",
+      "fefunca":"feFuncA",
+      "fefuncb":"feFuncB",
+      "fefuncg":"feFuncG",
+      "fefuncr":"feFuncR",
+      "fegaussianblur":"feGaussianBlur",
+      "feimage":"feImage",
+      "femerge":"feMerge",
+      "femergenode":"feMergeNode",
+      "femorphology":"feMorphology",
+      "feoffset":"feOffset",
+      "fepointlight":"fePointLight",
+      "fespecularlighting":"feSpecularLighting",
+      "fespotlight":"feSpotLight",
+      "fetile":"feTile",
+      "feturbulence":"feTurbulence",
+      "foreignobject":"foreignObject",
+      "glyphref":"glyphRef",
+      "lineargradient":"linearGradient",
+      "radialgradient":"radialGradient",
+      "textpath":"textPath"
+    };
+
+    var replace = replacements[token.name];
+    if (replace != null) {
+      token.name = replace;
+    }
+  }
+
+  Token processCharacters(CharactersToken token) {
+    if (token.data == "\u0000") {
+      token.data = "\uFFFD";
+    } else if (parser.framesetOK && !allWhitespace(token.data)) {
+      parser.framesetOK = false;
+    }
+    super.processCharacters(token);
+  }
+
+  Token processStartTag(StartTagToken token) {
+    var currentNode = tree.openElements.last;
+    if (breakoutElements.contains(token.name) ||
+        (token.name == "font" &&
+         (token.data.containsKey("color") ||
+          token.data.containsKey("face") ||
+          token.data.containsKey("size")))) {
+
+      parser.parseError(token.span,
+          "unexpected-html-element-in-foreign-content", {'name': token.name});
+      while (tree.openElements.last.namespace !=
+           tree.defaultNamespace &&
+           !parser.isHTMLIntegrationPoint(tree.openElements.last) &&
+           !parser.isMathMLTextIntegrationPoint(tree.openElements.last)) {
+        tree.openElements.removeLast();
+      }
+      return token;
+
+    } else {
+      if (currentNode.namespace == Namespaces.mathml) {
+        parser.adjustMathMLAttributes(token);
+      } else if (currentNode.namespace == Namespaces.svg) {
+        adjustSVGTagNames(token);
+        parser.adjustSVGAttributes(token);
+      }
+      parser.adjustForeignAttributes(token);
+      token.namespace = currentNode.namespace;
+      tree.insertElement(token);
+      if (token.selfClosing) {
+        tree.openElements.removeLast();
+        token.selfClosingAcknowledged = true;
+      }
+    }
+  }
+
+  Token processEndTag(EndTagToken token) {
+    var nodeIndex = tree.openElements.length - 1;
+    var node = tree.openElements.last;
+    if (node.tagName != token.name) {
+      parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
+    }
+
+    var newToken = null;
+    while (true) {
+      if (asciiUpper2Lower(node.tagName) == token.name) {
+        //XXX this isn't in the spec but it seems necessary
+        if (parser.phase == parser._inTableTextPhase) {
+          InTableTextPhase inTableText = parser.phase;
+          inTableText.flushCharacters();
+          parser.phase = inTableText.originalPhase;
+        }
+        while (tree.openElements.removeLast() != node) {
+          assert(tree.openElements.length > 0);
+        }
+        newToken = null;
+        break;
+      }
+      nodeIndex -= 1;
+
+      node = tree.openElements[nodeIndex];
+      if (node.namespace != tree.defaultNamespace) {
+        continue;
+      } else {
+        newToken = parser.phase.processEndTag(token);
+        break;
+      }
+    }
+    return newToken;
+  }
+}
+
+
+class AfterBodyPhase extends Phase {
+  AfterBodyPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    if (token.name == "html") return startTagHtml(token);
+    return startTagOther(token);
+  }
+
+  processEndTag(EndTagToken token) {
+    if (token.name == "html") return endTagHtml(token);
+    return endTagOther(token);
+  }
+
+  //Stop parsing
+  bool processEOF() => false;
+
+  Token processComment(CommentToken token) {
+    // This is needed because data is to be appended to the <html> element
+    // here and not to whatever is currently open.
+    tree.insertComment(token, tree.openElements[0]);
+  }
+
+  Token processCharacters(CharactersToken token) {
+    parser.parseError(token.span, "unexpected-char-after-body");
+    parser.phase = parser._inBodyPhase;
+    return token;
+  }
+
+  Token startTagHtml(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  Token startTagOther(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-after-body",
+        {"name": token.name});
+    parser.phase = parser._inBodyPhase;
+    return token;
+  }
+
+  void endTagHtml(Token token) {
+    if (parser.innerHTMLMode) {
+      parser.parseError(token.span, "unexpected-end-tag-after-body-innerhtml");
+    } else {
+      parser.phase = parser._afterAfterBodyPhase;
+    }
+  }
+
+  Token endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-after-body",
+        {"name": token.name});
+    parser.phase = parser._inBodyPhase;
+    return token;
+  }
+}
+
+class InFramesetPhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///in-frameset
+  InFramesetPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "frameset": return startTagFrameset(token);
+      case "frame": return startTagFrame(token);
+      case "noframes": return startTagNoframes(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "frameset": return endTagFrameset(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  bool processEOF() {
+    var last = tree.openElements.last;
+    if (last.tagName != "html") {
+      parser.parseError(last.sourceSpan, "eof-in-frameset");
+    } else {
+      assert(parser.innerHTMLMode);
+    }
+    return false;
+  }
+
+  Token processCharacters(CharactersToken token) {
+    parser.parseError(token.span, "unexpected-char-in-frameset");
+  }
+
+  void startTagFrameset(StartTagToken token) {
+    tree.insertElement(token);
+  }
+
+  void startTagFrame(StartTagToken token) {
+    tree.insertElement(token);
+    tree.openElements.removeLast();
+  }
+
+  Token startTagNoframes(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  Token startTagOther(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-in-frameset",
+        {"name": token.name});
+  }
+
+  void endTagFrameset(EndTagToken token) {
+    if (tree.openElements.last.tagName == "html") {
+      // innerHTML case
+      parser.parseError(token.span,
+          "unexpected-frameset-in-frameset-innerhtml");
+    } else {
+      tree.openElements.removeLast();
+    }
+    if (!parser.innerHTMLMode && tree.openElements.last.tagName != "frameset") {
+      // If we're not in innerHTML mode and the the current node is not a
+      // "frameset" element (anymore) then switch.
+      parser.phase = parser._afterFramesetPhase;
+    }
+  }
+
+  void endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-in-frameset",
+        {"name": token.name});
+  }
+}
+
+
+class AfterFramesetPhase extends Phase {
+  // http://www.whatwg.org/specs/web-apps/current-work///after3
+  AfterFramesetPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "noframes": return startTagNoframes(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  processEndTag(EndTagToken token) {
+    switch (token.name) {
+      case "html": return endTagHtml(token);
+      default: return endTagOther(token);
+    }
+  }
+
+  // Stop parsing
+  bool processEOF() => false;
+
+  Token processCharacters(CharactersToken token) {
+    parser.parseError(token.span, "unexpected-char-after-frameset");
+  }
+
+  Token startTagNoframes(StartTagToken token) {
+    return parser._inHeadPhase.processStartTag(token);
+  }
+
+  void startTagOther(StartTagToken token) {
+    parser.parseError(token.span, "unexpected-start-tag-after-frameset",
+        {"name": token.name});
+  }
+
+  void endTagHtml(EndTagToken token) {
+    parser.phase = parser._afterAfterFramesetPhase;
+  }
+
+  void endTagOther(EndTagToken token) {
+    parser.parseError(token.span, "unexpected-end-tag-after-frameset",
+        {"name": token.name});
+  }
+}
+
+
+class AfterAfterBodyPhase extends Phase {
+  AfterAfterBodyPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    if (token.name == 'html') return startTagHtml(token);
+    return startTagOther(token);
+  }
+
+  bool processEOF() => false;
+
+  Token processComment(CommentToken token) {
+    tree.insertComment(token, tree.document);
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    return parser._inBodyPhase.processSpaceCharacters(token);
+  }
+
+  Token processCharacters(CharactersToken token) {
+    parser.parseError(token.span, "expected-eof-but-got-char");
+    parser.phase = parser._inBodyPhase;
+    return token;
+  }
+
+  Token startTagHtml(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  Token startTagOther(StartTagToken token) {
+    parser.parseError(token.span, "expected-eof-but-got-start-tag",
+        {"name": token.name});
+    parser.phase = parser._inBodyPhase;
+    return token;
+  }
+
+  Token processEndTag(EndTagToken token) {
+    parser.parseError(token.span, "expected-eof-but-got-end-tag",
+        {"name": token.name});
+    parser.phase = parser._inBodyPhase;
+    return token;
+  }
+}
+
+class AfterAfterFramesetPhase extends Phase {
+  AfterAfterFramesetPhase(parser) : super(parser);
+
+  processStartTag(StartTagToken token) {
+    switch (token.name) {
+      case "html": return startTagHtml(token);
+      case "noframes": return startTagNoFrames(token);
+      default: return startTagOther(token);
+    }
+  }
+
+  bool processEOF() => false;
+
+  Token processComment(CommentToken token) {
+    tree.insertComment(token, tree.document);
+  }
+
+  Token processSpaceCharacters(SpaceCharactersToken token) {
+    return parser._inBodyPhase.processSpaceCharacters(token);
+  }
+
+  Token processCharacters(CharactersToken token) {
+    parser.parseError(token.span, "expected-eof-but-got-char");
+  }
+
+  Token startTagHtml(StartTagToken token) {
+    return parser._inBodyPhase.processStartTag(token);
+  }
+
+  Token startTagNoFrames(StartTagToken token) {
+    return parser._inHeadPhase.processStartTag(token);
+  }
+
+  void startTagOther(StartTagToken token) {
+    parser.parseError(token.span, "expected-eof-but-got-start-tag",
+        {"name": token.name});
+  }
+
+  Token processEndTag(EndTagToken token) {
+    parser.parseError(token.span, "expected-eof-but-got-end-tag",
+        {"name": token.name});
+  }
+}
+
+
+/** Error in parsed document. */
+class ParseError implements Exception {
+  final String errorCode;
+  final Span span;
+  final Map data;
+
+  ParseError(this.errorCode, this.span, this.data);
+
+  int get line => span.start.line;
+
+  int get column => span.start.column;
+
+  /**
+   * Gets the human readable error message for this error. Use
+   * [span.getLocationMessage] or [toString] to get a message including span
+   * information. If there is a file associated with the span, both
+   * [span.getLocationMessage] and [toString] are equivalent. Otherwise,
+   * [span.getLocationMessage] will not show any source url information, but
+   * [toString] will include 'ParserError:' as a prefix.
+   */
+  String get message => formatStr(errorMessages[errorCode], data);
+
+  String toString() {
+    var res = span.getLocationMessage(message);
+    return span.sourceUrl == null ? 'ParserError$res' : res;
+  }
+}
diff --git a/pkg/third_party/html5lib/lib/parser_console.dart b/pkg/third_party/html5lib/lib/parser_console.dart
new file mode 100644
index 0000000..7858ab2
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/parser_console.dart
@@ -0,0 +1,46 @@
+/**
+ * This library adds `dart:io` support to the HTML5 parser. Call
+ * [initDartIOSupport] before calling the [parse] methods and they will accept
+ * a [RandomAccessFile] as input, in addition to the other input types.
+ */
+library parser_console;
+
+import 'dart:io';
+import 'parser.dart';
+import 'src/inputstream.dart' as inputstream;
+
+/**
+ * Adds support to the [HtmlParser] for running on a console VM. In particular
+ * this means it will be able to handle `dart:io` and [RandomAccessFile]s as
+ * input to the various [parse] methods.
+ */
+void useConsole() {
+  inputstream.consoleSupport = new _ConsoleSupport();
+}
+
+class _ConsoleSupport extends inputstream.ConsoleSupport {
+  List<int> bytesFromFile(source) {
+    if (source is! RandomAccessFile) return null;
+    return readAllBytesFromFile(source);
+  }
+}
+
+// TODO(jmesserly): this should be `RandomAccessFile.readAllBytes`.
+/** Synchronously reads all bytes from the [file]. */
+List<int> readAllBytesFromFile(RandomAccessFile file) {
+  int length = file.lengthSync();
+  var bytes = new List<int>(length);
+
+  int bytesRead = 0;
+  while (bytesRead < length) {
+    int read = file.readIntoSync(bytes, bytesRead, length - bytesRead);
+    if (read <= 0) {
+      // This could happen if, for example, the file was resized while
+      // we're reading. Just shrink the bytes array and move on.
+      bytes = bytes.sublist(0, bytesRead);
+      break;
+    }
+    bytesRead += read;
+  }
+  return bytes;
+}
diff --git a/pkg/third_party/html5lib/lib/src/char_encodings.dart b/pkg/third_party/html5lib/lib/src/char_encodings.dart
new file mode 100644
index 0000000..610a8da
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/char_encodings.dart
@@ -0,0 +1,212 @@
+/** Decodes bytes using the correct name. See [decodeBytes]. */
+library char_encodings;
+
+import 'dart:collection';
+import 'dart:utf';
+
+// TODO(jmesserly): this function is conspicuously absent from dart:utf.
+/**
+ * Returns true if the [bytes] starts with a UTF-8 byte order mark.
+ * Since UTF-8 doesn't have byte order, it's somewhat of a misnomer, but it is
+ * used in HTML to detect the UTF-
+ */
+bool hasUtf8Bom(List<int> bytes, [int offset = 0, int length]) {
+  int end = length != null ? offset + length : bytes.length;
+  return (offset + 3) <= end &&
+      bytes[offset] == 0xEF &&
+      bytes[offset + 1] == 0xBB &&
+      bytes[offset + 2] == 0xBF;
+}
+
+// TODO(jmesserly): it's unfortunate that this has to be one-shot on the entire
+// file, but dart:utf does not expose stream-based decoders yet.
+/**
+ * Decodes the [bytes] with the provided [encoding] and returns an iterable for
+ * the codepoints. Supports the major unicode encodings as well as ascii and
+ * and windows-1252 encodings.
+ */
+Iterable<int> decodeBytes(String encoding, List<int> bytes,
+    [int offset = 0, int length,
+    int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
+  if (length == null) length = bytes.length;
+  final replace = replacementCodepoint;
+  switch (encoding) {
+    case 'ascii':
+      bytes = bytes.sublist(offset, offset + length);
+      // TODO(jmesserly): this was taken from runtime/bin/string_stream.dart
+      for (int byte in bytes) {
+        if (byte > 127) {
+          // TODO(jmesserly): ideally this would be DecoderException, like the
+          // one thrown in runtime/bin/string_stream.dart, but we don't want to
+          // depend on dart:io.
+          throw new FormatException("Illegal ASCII character $byte");
+        }
+      }
+      return bytes;
+
+    case 'windows-1252':
+    case 'cp1252':
+      return decodeWindows1252AsIterable(bytes, offset, length, replace);
+
+    case 'utf-8':
+      // NOTE: to match the behavior of the other decode functions, we eat the
+      // utf-8 BOM here.
+      if (hasUtf8Bom(bytes, offset, length)) {
+        offset += 3;
+        length -= 3;
+      }
+      return decodeUtf8AsIterable(bytes, offset, length, replace);
+
+    case 'utf-16':
+      return decodeUtf16AsIterable(bytes, offset, length, replace);
+    case 'utf-16-be':
+      return decodeUtf16beAsIterable(bytes, offset, length, true, replace);
+    case 'utf-16-le':
+      return decodeUtf16leAsIterable(bytes, offset, length, true, replace);
+
+    case 'utf-32':
+      return decodeUtf32AsIterable(bytes, offset, length, replace);
+    case 'utf-32-be':
+      return decodeUtf32beAsIterable(bytes, offset, length, true, replace);
+    case 'utf-32-le':
+      return decodeUtf32leAsIterable(bytes, offset, length, true, replace);
+
+    default:
+      throw new ArgumentError('Encoding $encoding not supported');
+  }
+}
+
+
+// TODO(jmesserly): use dart:utf once http://dartbug.com/6476 is fixed.
+/**
+ * Returns the code points for the [input]. This works like [String.charCodes]
+ * but it decodes UTF-16 surrogate pairs.
+ */
+List<int> toCodepoints(String input) {
+  var newCodes = <int>[];
+  for (int i = 0; i < input.length; i++) {
+    var c = input.codeUnitAt(i);
+    if (0xD800 <= c && c <= 0xDBFF) {
+      int next = i + 1;
+      if (next < input.length) {
+        var d = input.codeUnitAt(next);
+        if (0xDC00 <= d && d <= 0xDFFF) {
+          c = 0x10000 + ((c - 0xD800) << 10) + (d - 0xDC00);
+          i = next;
+        }
+      }
+    }
+    newCodes.add(c);
+  }
+  return newCodes;
+}
+
+
+/**
+ * Decodes [windows-1252](http://en.wikipedia.org/wiki/Windows-1252) bytes as an
+ * iterable. Thus, the consumer can only convert as much of the input as needed.
+ * Set the [replacementCharacter] to null to throw an [ArgumentError]
+ * rather than replace the bad value.
+ */
+IterableWindows1252Decoder decodeWindows1252AsIterable(List<int> bytes,
+    [int offset = 0, int length,
+    int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
+  return new IterableWindows1252Decoder(bytes, offset, length,
+      replacementCodepoint);
+}
+
+
+/**
+ * Return type of [decodeWindows1252AsIterable] and variants. The Iterable type
+ * provides an iterator on demand and the iterator will only translate bytes
+ * as requested by the user of the iterator. (Note: results are not cached.)
+ */
+class IterableWindows1252Decoder extends IterableBase<int> {
+  final List<int> bytes;
+  final int offset;
+  final int length;
+  final int replacementCodepoint;
+
+  IterableWindows1252Decoder(List<int> this.bytes, [int this.offset = 0,
+      int this.length = null,
+      int this.replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]);
+
+  Windows1252Decoder get iterator =>
+      new Windows1252Decoder(bytes, offset, length, replacementCodepoint);
+}
+
+
+/**
+ * Provides an iterator of Unicode codepoints from windows-1252 encoded bytes.
+ * The parameters can set an offset into a list of bytes (as int), limit the
+ * length of the values to be decoded, and override the default Unicode
+ * replacement character. Set the replacementCharacter to null to throw an
+ * ArgumentError rather than replace the bad value. The return value
+ * from this method can be used as an Iterable (e.g. in a for-loop).
+ */
+class Windows1252Decoder implements Iterator<int> {
+  final int replacementCodepoint;
+  final List<int> _bytes;
+  int _offset;
+  final int _length;
+
+  Windows1252Decoder(List<int> bytes, [int offset = 0, int length,
+      this.replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT])
+      : _bytes = bytes,
+        _offset = offset - 1,
+        _length = length == null ? bytes.length : length;
+
+  bool get _inRange => _offset >= 0 && _offset < _length;
+  int get current => _inRange ? _mapChar(_bytes[_offset]) : null;
+
+  bool moveNext() {
+    _offset++;
+    return _inRange;
+  }
+
+  int _mapChar(int char) {
+    // TODO(jmesserly): this is duplicating entitiesWindows1252 and
+    // replacementCharacters from constants.dart
+    switch (char) {
+      case 0x80: return 0x20AC; // EURO SIGN
+      case 0x82: return 0x201A; // SINGLE LOW-9 QUOTATION MARK
+      case 0x83: return 0x0192; // LATIN SMALL LETTER F WITH HOOK
+      case 0x84: return 0x201E; // DOUBLE LOW-9 QUOTATION MARK
+      case 0x85: return 0x2026; // HORIZONTAL ELLIPSIS
+      case 0x86: return 0x2020; // DAGGER
+      case 0x87: return 0x2021; // DOUBLE DAGGER
+      case 0x88: return 0x02C6; // MODIFIER LETTER CIRCUMFLEX ACCENT
+      case 0x89: return 0x2030; // PER MILLE SIGN
+      case 0x8A: return 0x0160; // LATIN CAPITAL LETTER S WITH CARON
+      case 0x8B: return 0x2039; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+      case 0x8C: return 0x0152; // LATIN CAPITAL LIGATURE OE
+      case 0x8E: return 0x017D; // LATIN CAPITAL LETTER Z WITH CARON
+      case 0x91: return 0x2018; // LEFT SINGLE QUOTATION MARK
+      case 0x92: return 0x2019; // RIGHT SINGLE QUOTATION MARK
+      case 0x93: return 0x201C; // LEFT DOUBLE QUOTATION MARK
+      case 0x94: return 0x201D; // RIGHT DOUBLE QUOTATION MARK
+      case 0x95: return 0x2022; // BULLET
+      case 0x96: return 0x2013; // EN DASH
+      case 0x97: return 0x2014; // EM DASH
+      case 0x98: return 0x02DC; // SMALL TILDE
+      case 0x99: return 0x2122; // TRADE MARK SIGN
+      case 0x9A: return 0x0161; // LATIN SMALL LETTER S WITH CARON
+      case 0x9B: return 0x203A; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+      case 0x9C: return 0x0153; // LATIN SMALL LIGATURE OE
+      case 0x9E: return 0x017E; // LATIN SMALL LETTER Z WITH CARON
+      case 0x9F: return 0x0178; // LATIN CAPITAL LETTER Y WITH DIAERESIS
+
+      case 0x81:
+      case 0x8D:
+      case 0x8F:
+      case 0x90:
+      case 0x9D:
+        if (replacementCodepoint == null) {
+          throw new ArgumentError(
+              "Invalid windows-1252 code point $char at $_offset");
+        }
+        return replacementCodepoint;
+    }
+    return char;
+  }
+}
diff --git a/pkg/third_party/html5lib/lib/src/constants.dart b/pkg/third_party/html5lib/lib/src/constants.dart
new file mode 100644
index 0000000..319ef3e
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/constants.dart
@@ -0,0 +1,3129 @@
+library constants;
+
+import 'utils.dart';
+import 'token.dart';
+
+// TODO(jmesserly): fix up the const lists. For the bigger ones, we need faster
+// lookup than linear search "contains". In the Python code they were
+// frozensets.
+
+final String EOF = null;
+
+class ReparseException implements Exception {
+  final String message;
+  ReparseException(this.message);
+  String toString() => "ReparseException: $message";
+}
+
+// TODO(jmesserly): assuming the programmatic name is not important, it would be
+// good to make these "static const" fields on an ErrorMessage class.
+/**
+ * These are error messages emitted by [HtmlParser]. The values use Python style
+ * string formatting, as implemented by [formatStr]. That function only supports
+ * the subset of format functionality used here.
+ */
+final Map<String, String> errorMessages = const {
+  "null-character":
+     "Null character in input stream, replaced with U+FFFD.",
+  "invalid-codepoint":
+     "Invalid codepoint in stream.",
+  "incorrectly-placed-solidus":
+     "Solidus (/) incorrectly placed in tag.",
+  "incorrect-cr-newline-entity":
+     "Incorrect CR newline entity, replaced with LF.",
+  "illegal-windows-1252-entity":
+     "Entity used with illegal number (windows-1252 reference).",
+  "cant-convert-numeric-entity":
+     "Numeric entity couldn't be converted to character "
+       "(codepoint U+%(charAsInt)08x).",
+  "illegal-codepoint-for-numeric-entity":
+     "Numeric entity represents an illegal codepoint: "
+       "U+%(charAsInt)08x.",
+  "numeric-entity-without-semicolon":
+     "Numeric entity didn't end with ';'.",
+  "expected-numeric-entity-but-got-eof":
+     "Numeric entity expected. Got end of file instead.",
+  "expected-numeric-entity":
+     "Numeric entity expected but none found.",
+  "named-entity-without-semicolon":
+     "Named entity didn't end with ';'.",
+  "expected-named-entity":
+     "Named entity expected. Got none.",
+  "attributes-in-end-tag":
+     "End tag contains unexpected attributes.",
+  'self-closing-flag-on-end-tag':
+      "End tag contains unexpected self-closing flag.",
+  "expected-tag-name-but-got-right-bracket":
+     "Expected tag name. Got '>' instead.",
+  "expected-tag-name-but-got-question-mark":
+     "Expected tag name. Got '?' instead. (HTML doesn't "
+       "support processing instructions.)",
+  "expected-tag-name":
+     "Expected tag name. Got something else instead",
+  "expected-closing-tag-but-got-right-bracket":
+     "Expected closing tag. Got '>' instead. Ignoring '</>'.",
+  "expected-closing-tag-but-got-eof":
+     "Expected closing tag. Unexpected end of file.",
+  "expected-closing-tag-but-got-char":
+     "Expected closing tag. Unexpected character '%(data)s' found.",
+  "eof-in-tag-name":
+     "Unexpected end of file in the tag name.",
+  "expected-attribute-name-but-got-eof":
+     "Unexpected end of file. Expected attribute name instead.",
+  "eof-in-attribute-name":
+     "Unexpected end of file in attribute name.",
+  "invalid-character-in-attribute-name":
+      "Invalid character in attribute name",
+  "duplicate-attribute":
+     "Dropped duplicate attribute on tag.",
+  "expected-end-of-tag-name-but-got-eof":
+     "Unexpected end of file. Expected = or end of tag.",
+  "expected-attribute-value-but-got-eof":
+     "Unexpected end of file. Expected attribute value.",
+  "expected-attribute-value-but-got-right-bracket":
+     "Expected attribute value. Got '>' instead.",
+  'equals-in-unquoted-attribute-value':
+      "Unexpected = in unquoted attribute",
+  'unexpected-character-in-unquoted-attribute-value':
+      "Unexpected character in unquoted attribute",
+  "invalid-character-after-attribute-name":
+     "Unexpected character after attribute name.",
+  "unexpected-character-after-attribute-value":
+     "Unexpected character after attribute value.",
+  "eof-in-attribute-value-double-quote":
+     "Unexpected end of file in attribute value (\".",
+  "eof-in-attribute-value-single-quote":
+     "Unexpected end of file in attribute value (').",
+  "eof-in-attribute-value-no-quotes":
+     "Unexpected end of file in attribute value.",
+  "unexpected-EOF-after-solidus-in-tag":
+      "Unexpected end of file in tag. Expected >",
+  "unexpected-character-after-soldius-in-tag":
+      "Unexpected character after / in tag. Expected >",
+  "expected-dashes-or-doctype":
+     "Expected '--' or 'DOCTYPE'. Not found.",
+  "unexpected-bang-after-double-dash-in-comment":
+      "Unexpected ! after -- in comment",
+  "unexpected-space-after-double-dash-in-comment":
+      "Unexpected space after -- in comment",
+  "incorrect-comment":
+     "Incorrect comment.",
+  "eof-in-comment":
+     "Unexpected end of file in comment.",
+  "eof-in-comment-end-dash":
+     "Unexpected end of file in comment (-)",
+  "unexpected-dash-after-double-dash-in-comment":
+     "Unexpected '-' after '--' found in comment.",
+  "eof-in-comment-double-dash":
+     "Unexpected end of file in comment (--).",
+  "eof-in-comment-end-space-state":
+     "Unexpected end of file in comment.",
+  "eof-in-comment-end-bang-state":
+     "Unexpected end of file in comment.",
+  "unexpected-char-in-comment":
+     "Unexpected character in comment found.",
+  "need-space-after-doctype":
+     "No space after literal string 'DOCTYPE'.",
+  "expected-doctype-name-but-got-right-bracket":
+     "Unexpected > character. Expected DOCTYPE name.",
+  "expected-doctype-name-but-got-eof":
+     "Unexpected end of file. Expected DOCTYPE name.",
+  "eof-in-doctype-name":
+     "Unexpected end of file in DOCTYPE name.",
+  "eof-in-doctype":
+     "Unexpected end of file in DOCTYPE.",
+  "expected-space-or-right-bracket-in-doctype":
+     "Expected space or '>'. Got '%(data)s'",
+  "unexpected-end-of-doctype":
+     "Unexpected end of DOCTYPE.",
+  "unexpected-char-in-doctype":
+     "Unexpected character in DOCTYPE.",
+  "eof-in-innerhtml":
+     "XXX innerHTML EOF",
+  "unexpected-doctype":
+     "Unexpected DOCTYPE. Ignored.",
+  "non-html-root":
+     "html needs to be the first start tag.",
+  "expected-doctype-but-got-eof":
+     "Unexpected End of file. Expected DOCTYPE.",
+  "unknown-doctype":
+     "Erroneous DOCTYPE.",
+  "expected-doctype-but-got-chars":
+     "Unexpected non-space characters. Expected DOCTYPE.",
+  "expected-doctype-but-got-start-tag":
+     "Unexpected start tag (%(name)s). Expected DOCTYPE.",
+  "expected-doctype-but-got-end-tag":
+     "Unexpected end tag (%(name)s). Expected DOCTYPE.",
+  "end-tag-after-implied-root":
+     "Unexpected end tag (%(name)s) after the (implied) root element.",
+  "expected-named-closing-tag-but-got-eof":
+     "Unexpected end of file. Expected end tag (%(name)s).",
+  "two-heads-are-not-better-than-one":
+     "Unexpected start tag head in existing head. Ignored.",
+  "unexpected-end-tag":
+     "Unexpected end tag (%(name)s). Ignored.",
+  "unexpected-start-tag-out-of-my-head":
+     "Unexpected start tag (%(name)s) that can be in head. Moved.",
+  "unexpected-start-tag":
+     "Unexpected start tag (%(name)s).",
+  "missing-end-tag":
+     "Missing end tag (%(name)s).",
+  "missing-end-tags":
+     "Missing end tags (%(name)s).",
+  "unexpected-start-tag-implies-end-tag":
+     "Unexpected start tag (%(startName)s) "
+       "implies end tag (%(endName)s).",
+  "unexpected-start-tag-treated-as":
+     "Unexpected start tag (%(originalName)s). Treated as %(newName)s.",
+  "deprecated-tag":
+     "Unexpected start tag %(name)s. Don't use it!",
+  "unexpected-start-tag-ignored":
+     "Unexpected start tag %(name)s. Ignored.",
+  "expected-one-end-tag-but-got-another":
+     "Unexpected end tag (%(gotName)s). "
+       "Missing end tag (%(expectedName)s).",
+  "end-tag-too-early":
+     "End tag (%(name)s) seen too early. Expected other end tag.",
+  "end-tag-too-early-named":
+     "Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).",
+  "end-tag-too-early-ignored":
+     "End tag (%(name)s) seen too early. Ignored.",
+  "adoption-agency-1.1":
+     "End tag (%(name)s) violates step 1, "
+       "paragraph 1 of the adoption agency algorithm.",
+  "adoption-agency-1.2":
+     "End tag (%(name)s) violates step 1, "
+       "paragraph 2 of the adoption agency algorithm.",
+  "adoption-agency-1.3":
+     "End tag (%(name)s) violates step 1, "
+       "paragraph 3 of the adoption agency algorithm.",
+  "unexpected-end-tag-treated-as":
+     "Unexpected end tag (%(originalName)s). Treated as %(newName)s.",
+  "no-end-tag":
+     "This element (%(name)s) has no end tag.",
+  "unexpected-implied-end-tag-in-table":
+     "Unexpected implied end tag (%(name)s) in the table phase.",
+  "unexpected-implied-end-tag-in-table-body":
+     "Unexpected implied end tag (%(name)s) in the table body phase.",
+  "unexpected-char-implies-table-voodoo":
+     "Unexpected non-space characters in "
+       "table context caused voodoo mode.",
+  "unexpected-hidden-input-in-table":
+     "Unexpected input with type hidden in table context.",
+  "unexpected-form-in-table":
+     "Unexpected form in table context.",
+  "unexpected-start-tag-implies-table-voodoo":
+     "Unexpected start tag (%(name)s) in "
+       "table context caused voodoo mode.",
+  "unexpected-end-tag-implies-table-voodoo":
+     "Unexpected end tag (%(name)s) in "
+       "table context caused voodoo mode.",
+  "unexpected-cell-in-table-body":
+     "Unexpected table cell start tag (%(name)s) "
+       "in the table body phase.",
+  "unexpected-cell-end-tag":
+     "Got table cell end tag (%(name)s) "
+       "while required end tags are missing.",
+  "unexpected-end-tag-in-table-body":
+     "Unexpected end tag (%(name)s) in the table body phase. Ignored.",
+  "unexpected-implied-end-tag-in-table-row":
+     "Unexpected implied end tag (%(name)s) in the table row phase.",
+  "unexpected-end-tag-in-table-row":
+     "Unexpected end tag (%(name)s) in the table row phase. Ignored.",
+  "unexpected-select-in-select":
+     "Unexpected select start tag in the select phase "
+       "treated as select end tag.",
+  "unexpected-input-in-select":
+     "Unexpected input start tag in the select phase.",
+  "unexpected-start-tag-in-select":
+     "Unexpected start tag token (%(name)s in the select phase. "
+       "Ignored.",
+  "unexpected-end-tag-in-select":
+     "Unexpected end tag (%(name)s) in the select phase. Ignored.",
+  "unexpected-table-element-start-tag-in-select-in-table":
+     "Unexpected table element start tag (%(name)s) in the select in table phase.",
+  "unexpected-table-element-end-tag-in-select-in-table":
+     "Unexpected table element end tag (%(name)s) in the select in table phase.",
+  "unexpected-char-after-body":
+     "Unexpected non-space characters in the after body phase.",
+  "unexpected-start-tag-after-body":
+     "Unexpected start tag token (%(name)s)"
+       " in the after body phase.",
+  "unexpected-end-tag-after-body":
+     "Unexpected end tag token (%(name)s)"
+       " in the after body phase.",
+  "unexpected-char-in-frameset":
+     "Unepxected characters in the frameset phase. Characters ignored.",
+  "unexpected-start-tag-in-frameset":
+     "Unexpected start tag token (%(name)s)"
+       " in the frameset phase. Ignored.",
+  "unexpected-frameset-in-frameset-innerhtml":
+     "Unexpected end tag token (frameset) "
+       "in the frameset phase (innerHTML).",
+  "unexpected-end-tag-in-frameset":
+     "Unexpected end tag token (%(name)s)"
+       " in the frameset phase. Ignored.",
+  "unexpected-char-after-frameset":
+     "Unexpected non-space characters in the "
+       "after frameset phase. Ignored.",
+  "unexpected-start-tag-after-frameset":
+     "Unexpected start tag (%(name)s)"
+       " in the after frameset phase. Ignored.",
+  "unexpected-end-tag-after-frameset":
+     "Unexpected end tag (%(name)s)"
+       " in the after frameset phase. Ignored.",
+  "unexpected-end-tag-after-body-innerhtml":
+     "Unexpected end tag after body(innerHtml)",
+  "expected-eof-but-got-char":
+     "Unexpected non-space characters. Expected end of file.",
+  "expected-eof-but-got-start-tag":
+     "Unexpected start tag (%(name)s)"
+       ". Expected end of file.",
+  "expected-eof-but-got-end-tag":
+     "Unexpected end tag (%(name)s)"
+       ". Expected end of file.",
+  "eof-in-table":
+     "Unexpected end of file. Expected table content.",
+  "eof-in-select":
+     "Unexpected end of file. Expected select content.",
+  "eof-in-frameset":
+     "Unexpected end of file. Expected frameset content.",
+  "eof-in-script-in-script":
+     "Unexpected end of file. Expected script content.",
+  "eof-in-foreign-lands":
+     "Unexpected end of file. Expected foreign content",
+  "non-void-element-with-trailing-solidus":
+     "Trailing solidus not allowed on element %(name)s",
+  "unexpected-html-element-in-foreign-content":
+     "Element %(name)s not allowed in a non-html context",
+  "unexpected-end-tag-before-html":
+      "Unexpected end tag (%(name)s) before html.",
+  "undefined-error":
+      "Undefined error (this sucks and should be fixed)",
+};
+
+class Namespaces {
+  static const html = "http://www.w3.org/1999/xhtml";
+  static const mathml = "http://www.w3.org/1998/Math/MathML";
+  static const svg = "http://www.w3.org/2000/svg";
+  static const xlink = "http://www.w3.org/1999/xlink";
+  static const xml = "http://www.w3.org/XML/1998/namespace";
+  static const xmlns = "http://www.w3.org/2000/xmlns/";
+  Namespaces._();
+
+  static String getPrefix(String url) {
+    switch (url) {
+      case html: return 'html';
+      case mathml: return 'math';
+      case svg: return 'svg';
+      case xlink: return 'xlink';
+      case xml: return 'xml';
+      case xmlns: return 'xmlns';
+      default: throw new ArgumentError(url);
+    }
+  }
+}
+
+final List scopingElements = const [
+  const Pair(Namespaces.html, "applet"),
+  const Pair(Namespaces.html, "caption"),
+  const Pair(Namespaces.html, "html"),
+  const Pair(Namespaces.html, "marquee"),
+  const Pair(Namespaces.html, "object"),
+  const Pair(Namespaces.html, "table"),
+  const Pair(Namespaces.html, "td"),
+  const Pair(Namespaces.html, "th"),
+  const Pair(Namespaces.mathml, "mi"),
+  const Pair(Namespaces.mathml, "mo"),
+  const Pair(Namespaces.mathml, "mn"),
+  const Pair(Namespaces.mathml, "ms"),
+  const Pair(Namespaces.mathml, "mtext"),
+  const Pair(Namespaces.mathml, "annotation-xml"),
+  const Pair(Namespaces.svg, "foreignObject"),
+  const Pair(Namespaces.svg, "desc"),
+  const Pair(Namespaces.svg, "title")
+];
+
+
+final formattingElements = const [
+  const Pair(Namespaces.html, "a"),
+  const Pair(Namespaces.html, "b"),
+  const Pair(Namespaces.html, "big"),
+  const Pair(Namespaces.html, "code"),
+  const Pair(Namespaces.html, "em"),
+  const Pair(Namespaces.html, "font"),
+  const Pair(Namespaces.html, "i"),
+  const Pair(Namespaces.html, "nobr"),
+  const Pair(Namespaces.html, "s"),
+  const Pair(Namespaces.html, "small"),
+  const Pair(Namespaces.html, "strike"),
+  const Pair(Namespaces.html, "strong"),
+  const Pair(Namespaces.html, "tt"),
+  const Pair(Namespaces.html, "")
+];
+
+final specialElements = const [
+  const Pair(Namespaces.html, "address"),
+  const Pair(Namespaces.html, "applet"),
+  const Pair(Namespaces.html, "area"),
+  const Pair(Namespaces.html, "article"),
+  const Pair(Namespaces.html, "aside"),
+  const Pair(Namespaces.html, "base"),
+  const Pair(Namespaces.html, "basefont"),
+  const Pair(Namespaces.html, "bgsound"),
+  const Pair(Namespaces.html, "blockquote"),
+  const Pair(Namespaces.html, "body"),
+  const Pair(Namespaces.html, "br"),
+  const Pair(Namespaces.html, "button"),
+  const Pair(Namespaces.html, "caption"),
+  const Pair(Namespaces.html, "center"),
+  const Pair(Namespaces.html, "col"),
+  const Pair(Namespaces.html, "colgroup"),
+  const Pair(Namespaces.html, "command"),
+  const Pair(Namespaces.html, "dd"),
+  const Pair(Namespaces.html, "details"),
+  const Pair(Namespaces.html, "dir"),
+  const Pair(Namespaces.html, "div"),
+  const Pair(Namespaces.html, "dl"),
+  const Pair(Namespaces.html, "dt"),
+  const Pair(Namespaces.html, "embed"),
+  const Pair(Namespaces.html, "fieldset"),
+  const Pair(Namespaces.html, "figure"),
+  const Pair(Namespaces.html, "footer"),
+  const Pair(Namespaces.html, "form"),
+  const Pair(Namespaces.html, "frame"),
+  const Pair(Namespaces.html, "frameset"),
+  const Pair(Namespaces.html, "h1"),
+  const Pair(Namespaces.html, "h2"),
+  const Pair(Namespaces.html, "h3"),
+  const Pair(Namespaces.html, "h4"),
+  const Pair(Namespaces.html, "h5"),
+  const Pair(Namespaces.html, "h6"),
+  const Pair(Namespaces.html, "head"),
+  const Pair(Namespaces.html, "header"),
+  const Pair(Namespaces.html, "hr"),
+  const Pair(Namespaces.html, "html"),
+  const Pair(Namespaces.html, "iframe"),
+  // Note that image is commented out in the spec as "this isn't an
+  // element that can end up on the stack, so it doesn't matter,"
+  const Pair(Namespaces.html, "image"),
+  const Pair(Namespaces.html, "img"),
+  const Pair(Namespaces.html, "input"),
+  const Pair(Namespaces.html, "isindex"),
+  const Pair(Namespaces.html, "li"),
+  const Pair(Namespaces.html, "link"),
+  const Pair(Namespaces.html, "listing"),
+  const Pair(Namespaces.html, "marquee"),
+  const Pair(Namespaces.html, "men"),
+  const Pair(Namespaces.html, "meta"),
+  const Pair(Namespaces.html, "nav"),
+  const Pair(Namespaces.html, "noembed"),
+  const Pair(Namespaces.html, "noframes"),
+  const Pair(Namespaces.html, "noscript"),
+  const Pair(Namespaces.html, "object"),
+  const Pair(Namespaces.html, "ol"),
+  const Pair(Namespaces.html, "p"),
+  const Pair(Namespaces.html, "param"),
+  const Pair(Namespaces.html, "plaintext"),
+  const Pair(Namespaces.html, "pre"),
+  const Pair(Namespaces.html, "script"),
+  const Pair(Namespaces.html, "section"),
+  const Pair(Namespaces.html, "select"),
+  const Pair(Namespaces.html, "style"),
+  const Pair(Namespaces.html, "table"),
+  const Pair(Namespaces.html, "tbody"),
+  const Pair(Namespaces.html, "td"),
+  const Pair(Namespaces.html, "textarea"),
+  const Pair(Namespaces.html, "tfoot"),
+  const Pair(Namespaces.html, "th"),
+  const Pair(Namespaces.html, "thead"),
+  const Pair(Namespaces.html, "title"),
+  const Pair(Namespaces.html, "tr"),
+  const Pair(Namespaces.html, "ul"),
+  const Pair(Namespaces.html, "wbr"),
+  const Pair(Namespaces.html, "xmp"),
+  const Pair(Namespaces.svg, "foreignObject")
+];
+
+final htmlIntegrationPointElements = const [
+  const Pair(Namespaces.mathml, "annotaion-xml"),
+  const Pair(Namespaces.svg, "foreignObject"),
+  const Pair(Namespaces.svg, "desc"),
+  const Pair(Namespaces.svg, "title")
+];
+
+final mathmlTextIntegrationPointElements = const [
+  const Pair(Namespaces.mathml, "mi"),
+  const Pair(Namespaces.mathml, "mo"),
+  const Pair(Namespaces.mathml, "mn"),
+  const Pair(Namespaces.mathml, "ms"),
+  const Pair(Namespaces.mathml, "mtext")
+];
+
+final spaceCharacters = " \n\r\t\u000C";
+
+const int NEWLINE = 10;
+const int RETURN = 13;
+
+bool isWhitespace(String char) {
+  if (char == null) return false;
+  return isWhitespaceCC(char.codeUnitAt(0));
+}
+
+bool isWhitespaceCC(int charCode) {
+  switch (charCode) {
+    case 9:  // '\t'
+    case NEWLINE: // '\n'
+    case 12: // '\f'
+    case RETURN: // '\r'
+    case 32: // ' '
+      return true;
+  }
+  return false;
+}
+
+final List<String> tableInsertModeElements = const [
+  "table",
+  "tbody",
+  "tfoot",
+  "thead",
+  "tr"
+];
+
+// TODO(jmesserly): remove these in favor of the test functions
+final asciiLetters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+final ZERO = 48;
+final LOWER_A = 97;
+final LOWER_Z = 122;
+final UPPER_A = 65;
+final UPPER_Z = 90;
+
+bool isLetterOrDigit(String char) => isLetter(char) || isDigit(char);
+
+// Note: this is intentially ASCII only
+bool isLetter(String char) {
+  if (char == null) return false;
+  int cc = char.codeUnitAt(0);
+  return cc >= LOWER_A && cc <= LOWER_Z || cc >= UPPER_A && cc <= UPPER_Z;
+}
+
+bool isDigit(String char) {
+  if (char == null) return false;
+  int cc = char.codeUnitAt(0);
+  return cc >= ZERO && cc < ZERO + 10;
+}
+
+bool isHexDigit(String char) {
+  if (char == null) return false;
+  switch (char.codeUnitAt(0)) {
+    case 48: case 49: case 50: case 51: case 52: // '0' - '4'
+    case 53: case 54: case 55: case 56: case 57: // '5' - '9'
+    case 65: case 66: case 67: case 68: case 69: case 70: // 'A' - 'F'
+    case 97: case 98: case 99: case 100: case 101: case 102: // 'a' - 'f'
+      return true;
+  }
+  return false;
+}
+
+// Note: based on the original Python code, I assume we only want to convert
+// ASCII chars to.toLowerCase() case, unlike Dart's toLowerCase function.
+String asciiUpper2Lower(String text) {
+  if (text == null) return null;
+  var result = new List<int>(text.length);
+  for (int i = 0; i < text.length; i++) {
+    var c = text.codeUnitAt(i);
+    if (c >= UPPER_A && c <= UPPER_Z) {
+      c += LOWER_A - UPPER_A;
+    }
+    result[i] = c;
+  }
+  return new String.fromCharCodes(result);
+}
+
+// Heading elements need to be ordered
+final headingElements = const [
+  "h1",
+  "h2",
+  "h3",
+  "h4",
+  "h5",
+  "h6"
+];
+
+final cdataElements = const ['title', 'textarea'];
+
+final rcdataElements = const [
+  'style',
+  'script',
+  'xmp',
+  'iframe',
+  'noembed',
+  'noframes',
+  'noscript'
+];
+
+final Map<String, List<String>> booleanAttributes = const {
+  "": const ["irrelevant",],
+  "style": const ["scoped",],
+  "img": const ["ismap",],
+  "audio": const ["autoplay","controls"],
+  "video": const ["autoplay","controls"],
+  "script": const ["defer", "async"],
+  "details": const ["open",],
+  "datagrid": const ["multiple", "disabled"],
+  "command": const ["hidden", "disabled", "checked", "default"],
+  "hr": const ["noshade"],
+  "men": const ["autosubmit",],
+  "fieldset": const ["disabled", "readonly"],
+  "option": const ["disabled", "readonly", "selected"],
+  "optgroup": const ["disabled", "readonly"],
+  "button": const ["disabled", "autofocus"],
+  "input": const ["disabled", "readonly", "required", "autofocus", "checked", "ismap"],
+  "select": const ["disabled", "readonly", "autofocus", "multiple"],
+  "output": const ["disabled", "readonly"],
+};
+
+// entitiesWindows1252 has to be _ordered_ and needs to have an index. It
+// therefore can't be a frozenset.
+final List<int> entitiesWindows1252 = const [
+  8364,  // 0x80  0x20AC  EURO SIGN
+  65533, // 0x81          UNDEFINED
+  8218,  // 0x82  0x201A  SINGLE LOW-9 QUOTATION MARK
+  402,   // 0x83  0x0192  LATIN SMALL LETTER F WITH HOOK
+  8222,  // 0x84  0x201E  DOUBLE LOW-9 QUOTATION MARK
+  8230,  // 0x85  0x2026  HORIZONTAL ELLIPSIS
+  8224,  // 0x86  0x2020  DAGGER
+  8225,  // 0x87  0x2021  DOUBLE DAGGER
+  710,   // 0x88  0x02C6  MODIFIER LETTER CIRCUMFLEX ACCENT
+  8240,  // 0x89  0x2030  PER MILLE SIGN
+  352,   // 0x8A  0x0160  LATIN CAPITAL LETTER S WITH CARON
+  8249,  // 0x8B  0x2039  SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+  338,   // 0x8C  0x0152  LATIN CAPITAL LIGATURE OE
+  65533, // 0x8D          UNDEFINED
+  381,   // 0x8E  0x017D  LATIN CAPITAL LETTER Z WITH CARON
+  65533, // 0x8F          UNDEFINED
+  65533, // 0x90          UNDEFINED
+  8216,  // 0x91  0x2018  LEFT SINGLE QUOTATION MARK
+  8217,  // 0x92  0x2019  RIGHT SINGLE QUOTATION MARK
+  8220,  // 0x93  0x201C  LEFT DOUBLE QUOTATION MARK
+  8221,  // 0x94  0x201D  RIGHT DOUBLE QUOTATION MARK
+  8226,  // 0x95  0x2022  BULLET
+  8211,  // 0x96  0x2013  EN DASH
+  8212,  // 0x97  0x2014  EM DASH
+  732,   // 0x98  0x02DC  SMALL TILDE
+  8482,  // 0x99  0x2122  TRADE MARK SIGN
+  353,   // 0x9A  0x0161  LATIN SMALL LETTER S WITH CARON
+  8250,  // 0x9B  0x203A  SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+  339,   // 0x9C  0x0153  LATIN SMALL LIGATURE OE
+  65533, // 0x9D          UNDEFINED
+  382,   // 0x9E  0x017E  LATIN SMALL LETTER Z WITH CARON
+  376    // 0x9F  0x0178  LATIN CAPITAL LETTER Y WITH DIAERESIS
+];
+
+final xmlEntities = const ['lt;', 'gt;', 'amp;', 'apos;', 'quot;'];
+
+final Map<String, String> entities = const {
+  "AElig": "\xc6",
+  "AElig;": "\xc6",
+  "AMP": "&",
+  "AMP;": "&",
+  "Aacute": "\xc1",
+  "Aacute;": "\xc1",
+  "Abreve;": "\u0102",
+  "Acirc": "\xc2",
+  "Acirc;": "\xc2",
+  "Acy;": "\u0410",
+  "Afr;": "\u{01d504}",
+  "Agrave": "\xc0",
+  "Agrave;": "\xc0",
+  "Alpha;": "\u0391",
+  "Amacr;": "\u0100",
+  "And;": "\u2a53",
+  "Aogon;": "\u0104",
+  "Aopf;": "\u{01d538}",
+  "ApplyFunction;": "\u2061",
+  "Aring": "\xc5",
+  "Aring;": "\xc5",
+  "Ascr;": "\u{01d49c}",
+  "Assign;": "\u2254",
+  "Atilde": "\xc3",
+  "Atilde;": "\xc3",
+  "Auml": "\xc4",
+  "Auml;": "\xc4",
+  "Backslash;": "\u2216",
+  "Barv;": "\u2ae7",
+  "Barwed;": "\u2306",
+  "Bcy;": "\u0411",
+  "Because;": "\u2235",
+  "Bernoullis;": "\u212c",
+  "Beta;": "\u0392",
+  "Bfr;": "\u{01d505}",
+  "Bopf;": "\u{01d539}",
+  "Breve;": "\u02d8",
+  "Bscr;": "\u212c",
+  "Bumpeq;": "\u224e",
+  "CHcy;": "\u0427",
+  "COPY": "\xa9",
+  "COPY;": "\xa9",
+  "Cacute;": "\u0106",
+  "Cap;": "\u22d2",
+  "CapitalDifferentialD;": "\u2145",
+  "Cayleys;": "\u212d",
+  "Ccaron;": "\u010c",
+  "Ccedil": "\xc7",
+  "Ccedil;": "\xc7",
+  "Ccirc;": "\u0108",
+  "Cconint;": "\u2230",
+  "Cdot;": "\u010a",
+  "Cedilla;": "\xb8",
+  "CenterDot;": "\xb7",
+  "Cfr;": "\u212d",
+  "Chi;": "\u03a7",
+  "CircleDot;": "\u2299",
+  "CircleMinus;": "\u2296",
+  "CirclePlus;": "\u2295",
+  "CircleTimes;": "\u2297",
+  "ClockwiseContourIntegral;": "\u2232",
+  "CloseCurlyDoubleQuote;": "\u201d",
+  "CloseCurlyQuote;": "\u2019",
+  "Colon;": "\u2237",
+  "Colone;": "\u2a74",
+  "Congruent;": "\u2261",
+  "Conint;": "\u222f",
+  "ContourIntegral;": "\u222e",
+  "Copf;": "\u2102",
+  "Coproduct;": "\u2210",
+  "CounterClockwiseContourIntegral;": "\u2233",
+  "Cross;": "\u2a2f",
+  "Cscr;": "\u{01d49e}",
+  "Cup;": "\u22d3",
+  "CupCap;": "\u224d",
+  "DD;": "\u2145",
+  "DDotrahd;": "\u2911",
+  "DJcy;": "\u0402",
+  "DScy;": "\u0405",
+  "DZcy;": "\u040f",
+  "Dagger;": "\u2021",
+  "Darr;": "\u21a1",
+  "Dashv;": "\u2ae4",
+  "Dcaron;": "\u010e",
+  "Dcy;": "\u0414",
+  "Del;": "\u2207",
+  "Delta;": "\u0394",
+  "Dfr;": "\u{01d507}",
+  "DiacriticalAcute;": "\xb4",
+  "DiacriticalDot;": "\u02d9",
+  "DiacriticalDoubleAcute;": "\u02dd",
+  "DiacriticalGrave;": "`",
+  "DiacriticalTilde;": "\u02dc",
+  "Diamond;": "\u22c4",
+  "DifferentialD;": "\u2146",
+  "Dopf;": "\u{01d53b}",
+  "Dot;": "\xa8",
+  "DotDot;": "\u20dc",
+  "DotEqual;": "\u2250",
+  "DoubleContourIntegral;": "\u222f",
+  "DoubleDot;": "\xa8",
+  "DoubleDownArrow;": "\u21d3",
+  "DoubleLeftArrow;": "\u21d0",
+  "DoubleLeftRightArrow;": "\u21d4",
+  "DoubleLeftTee;": "\u2ae4",
+  "DoubleLongLeftArrow;": "\u27f8",
+  "DoubleLongLeftRightArrow;": "\u27fa",
+  "DoubleLongRightArrow;": "\u27f9",
+  "DoubleRightArrow;": "\u21d2",
+  "DoubleRightTee;": "\u22a8",
+  "DoubleUpArrow;": "\u21d1",
+  "DoubleUpDownArrow;": "\u21d5",
+  "DoubleVerticalBar;": "\u2225",
+  "DownArrow;": "\u2193",
+  "DownArrowBar;": "\u2913",
+  "DownArrowUpArrow;": "\u21f5",
+  "DownBreve;": "\u0311",
+  "DownLeftRightVector;": "\u2950",
+  "DownLeftTeeVector;": "\u295e",
+  "DownLeftVector;": "\u21bd",
+  "DownLeftVectorBar;": "\u2956",
+  "DownRightTeeVector;": "\u295f",
+  "DownRightVector;": "\u21c1",
+  "DownRightVectorBar;": "\u2957",
+  "DownTee;": "\u22a4",
+  "DownTeeArrow;": "\u21a7",
+  "Downarrow;": "\u21d3",
+  "Dscr;": "\u{01d49f}",
+  "Dstrok;": "\u0110",
+  "ENG;": "\u014a",
+  "ETH": "\xd0",
+  "ETH;": "\xd0",
+  "Eacute": "\xc9",
+  "Eacute;": "\xc9",
+  "Ecaron;": "\u011a",
+  "Ecirc": "\xca",
+  "Ecirc;": "\xca",
+  "Ecy;": "\u042d",
+  "Edot;": "\u0116",
+  "Efr;": "\u{01d508}",
+  "Egrave": "\xc8",
+  "Egrave;": "\xc8",
+  "Element;": "\u2208",
+  "Emacr;": "\u0112",
+  "EmptySmallSquare;": "\u25fb",
+  "EmptyVerySmallSquare;": "\u25ab",
+  "Eogon;": "\u0118",
+  "Eopf;": "\u{01d53c}",
+  "Epsilon;": "\u0395",
+  "Equal;": "\u2a75",
+  "EqualTilde;": "\u2242",
+  "Equilibrium;": "\u21cc",
+  "Escr;": "\u2130",
+  "Esim;": "\u2a73",
+  "Eta;": "\u0397",
+  "Euml": "\xcb",
+  "Euml;": "\xcb",
+  "Exists;": "\u2203",
+  "ExponentialE;": "\u2147",
+  "Fcy;": "\u0424",
+  "Ffr;": "\u{01d509}",
+  "FilledSmallSquare;": "\u25fc",
+  "FilledVerySmallSquare;": "\u25aa",
+  "Fopf;": "\u{01d53d}",
+  "ForAll;": "\u2200",
+  "Fouriertrf;": "\u2131",
+  "Fscr;": "\u2131",
+  "GJcy;": "\u0403",
+  "GT": ">",
+  "GT;": ">",
+  "Gamma;": "\u0393",
+  "Gammad;": "\u03dc",
+  "Gbreve;": "\u011e",
+  "Gcedil;": "\u0122",
+  "Gcirc;": "\u011c",
+  "Gcy;": "\u0413",
+  "Gdot;": "\u0120",
+  "Gfr;": "\u{01d50a}",
+  "Gg;": "\u22d9",
+  "Gopf;": "\u{01d53e}",
+  "GreaterEqual;": "\u2265",
+  "GreaterEqualLess;": "\u22db",
+  "GreaterFullEqual;": "\u2267",
+  "GreaterGreater;": "\u2aa2",
+  "GreaterLess;": "\u2277",
+  "GreaterSlantEqual;": "\u2a7e",
+  "GreaterTilde;": "\u2273",
+  "Gscr;": "\u{01d4a2}",
+  "Gt;": "\u226b",
+  "HARDcy;": "\u042a",
+  "Hacek;": "\u02c7",
+  "Hat;": "^",
+  "Hcirc;": "\u0124",
+  "Hfr;": "\u210c",
+  "HilbertSpace;": "\u210b",
+  "Hopf;": "\u210d",
+  "HorizontalLine;": "\u2500",
+  "Hscr;": "\u210b",
+  "Hstrok;": "\u0126",
+  "HumpDownHump;": "\u224e",
+  "HumpEqual;": "\u224f",
+  "IEcy;": "\u0415",
+  "IJlig;": "\u0132",
+  "IOcy;": "\u0401",
+  "Iacute": "\xcd",
+  "Iacute;": "\xcd",
+  "Icirc": "\xce",
+  "Icirc;": "\xce",
+  "Icy;": "\u0418",
+  "Idot;": "\u0130",
+  "Ifr;": "\u2111",
+  "Igrave": "\xcc",
+  "Igrave;": "\xcc",
+  "Im;": "\u2111",
+  "Imacr;": "\u012a",
+  "ImaginaryI;": "\u2148",
+  "Implies;": "\u21d2",
+  "Int;": "\u222c",
+  "Integral;": "\u222b",
+  "Intersection;": "\u22c2",
+  "InvisibleComma;": "\u2063",
+  "InvisibleTimes;": "\u2062",
+  "Iogon;": "\u012e",
+  "Iopf;": "\u{01d540}",
+  "Iota;": "\u0399",
+  "Iscr;": "\u2110",
+  "Itilde;": "\u0128",
+  "Iukcy;": "\u0406",
+  "Iuml": "\xcf",
+  "Iuml;": "\xcf",
+  "Jcirc;": "\u0134",
+  "Jcy;": "\u0419",
+  "Jfr;": "\u{01d50d}",
+  "Jopf;": "\u{01d541}",
+  "Jscr;": "\u{01d4a5}",
+  "Jsercy;": "\u0408",
+  "Jukcy;": "\u0404",
+  "KHcy;": "\u0425",
+  "KJcy;": "\u040c",
+  "Kappa;": "\u039a",
+  "Kcedil;": "\u0136",
+  "Kcy;": "\u041a",
+  "Kfr;": "\u{01d50e}",
+  "Kopf;": "\u{01d542}",
+  "Kscr;": "\u{01d4a6}",
+  "LJcy;": "\u0409",
+  "LT": "<",
+  "LT;": "<",
+  "Lacute;": "\u0139",
+  "Lambda;": "\u039b",
+  "Lang;": "\u27ea",
+  "Laplacetrf;": "\u2112",
+  "Larr;": "\u219e",
+  "Lcaron;": "\u013d",
+  "Lcedil;": "\u013b",
+  "Lcy;": "\u041b",
+  "LeftAngleBracket;": "\u27e8",
+  "LeftArrow;": "\u2190",
+  "LeftArrowBar;": "\u21e4",
+  "LeftArrowRightArrow;": "\u21c6",
+  "LeftCeiling;": "\u2308",
+  "LeftDoubleBracket;": "\u27e6",
+  "LeftDownTeeVector;": "\u2961",
+  "LeftDownVector;": "\u21c3",
+  "LeftDownVectorBar;": "\u2959",
+  "LeftFloor;": "\u230a",
+  "LeftRightArrow;": "\u2194",
+  "LeftRightVector;": "\u294e",
+  "LeftTee;": "\u22a3",
+  "LeftTeeArrow;": "\u21a4",
+  "LeftTeeVector;": "\u295a",
+  "LeftTriangle;": "\u22b2",
+  "LeftTriangleBar;": "\u29cf",
+  "LeftTriangleEqual;": "\u22b4",
+  "LeftUpDownVector;": "\u2951",
+  "LeftUpTeeVector;": "\u2960",
+  "LeftUpVector;": "\u21bf",
+  "LeftUpVectorBar;": "\u2958",
+  "LeftVector;": "\u21bc",
+  "LeftVectorBar;": "\u2952",
+  "Leftarrow;": "\u21d0",
+  "Leftrightarrow;": "\u21d4",
+  "LessEqualGreater;": "\u22da",
+  "LessFullEqual;": "\u2266",
+  "LessGreater;": "\u2276",
+  "LessLess;": "\u2aa1",
+  "LessSlantEqual;": "\u2a7d",
+  "LessTilde;": "\u2272",
+  "Lfr;": "\u{01d50f}",
+  "Ll;": "\u22d8",
+  "Lleftarrow;": "\u21da",
+  "Lmidot;": "\u013f",
+  "LongLeftArrow;": "\u27f5",
+  "LongLeftRightArrow;": "\u27f7",
+  "LongRightArrow;": "\u27f6",
+  "Longleftarrow;": "\u27f8",
+  "Longleftrightarrow;": "\u27fa",
+  "Longrightarrow;": "\u27f9",
+  "Lopf;": "\u{01d543}",
+  "LowerLeftArrow;": "\u2199",
+  "LowerRightArrow;": "\u2198",
+  "Lscr;": "\u2112",
+  "Lsh;": "\u21b0",
+  "Lstrok;": "\u0141",
+  "Lt;": "\u226a",
+  "Map;": "\u2905",
+  "Mcy;": "\u041c",
+  "MediumSpace;": "\u205f",
+  "Mellintrf;": "\u2133",
+  "Mfr;": "\u{01d510}",
+  "MinusPlus;": "\u2213",
+  "Mopf;": "\u{01d544}",
+  "Mscr;": "\u2133",
+  "Mu;": "\u039c",
+  "NJcy;": "\u040a",
+  "Nacute;": "\u0143",
+  "Ncaron;": "\u0147",
+  "Ncedil;": "\u0145",
+  "Ncy;": "\u041d",
+  "NegativeMediumSpace;": "\u200b",
+  "NegativeThickSpace;": "\u200b",
+  "NegativeThinSpace;": "\u200b",
+  "NegativeVeryThinSpace;": "\u200b",
+  "NestedGreaterGreater;": "\u226b",
+  "NestedLessLess;": "\u226a",
+  "NewLine;": "\n",
+  "Nfr;": "\u{01d511}",
+  "NoBreak;": "\u2060",
+  "NonBreakingSpace;": "\xa0",
+  "Nopf;": "\u2115",
+  "Not;": "\u2aec",
+  "NotCongruent;": "\u2262",
+  "NotCupCap;": "\u226d",
+  "NotDoubleVerticalBar;": "\u2226",
+  "NotElement;": "\u2209",
+  "NotEqual;": "\u2260",
+  "NotEqualTilde;": "\u2242\u0338",
+  "NotExists;": "\u2204",
+  "NotGreater;": "\u226f",
+  "NotGreaterEqual;": "\u2271",
+  "NotGreaterFullEqual;": "\u2267\u0338",
+  "NotGreaterGreater;": "\u226b\u0338",
+  "NotGreaterLess;": "\u2279",
+  "NotGreaterSlantEqual;": "\u2a7e\u0338",
+  "NotGreaterTilde;": "\u2275",
+  "NotHumpDownHump;": "\u224e\u0338",
+  "NotHumpEqual;": "\u224f\u0338",
+  "NotLeftTriangle;": "\u22ea",
+  "NotLeftTriangleBar;": "\u29cf\u0338",
+  "NotLeftTriangleEqual;": "\u22ec",
+  "NotLess;": "\u226e",
+  "NotLessEqual;": "\u2270",
+  "NotLessGreater;": "\u2278",
+  "NotLessLess;": "\u226a\u0338",
+  "NotLessSlantEqual;": "\u2a7d\u0338",
+  "NotLessTilde;": "\u2274",
+  "NotNestedGreaterGreater;": "\u2aa2\u0338",
+  "NotNestedLessLess;": "\u2aa1\u0338",
+  "NotPrecedes;": "\u2280",
+  "NotPrecedesEqual;": "\u2aaf\u0338",
+  "NotPrecedesSlantEqual;": "\u22e0",
+  "NotReverseElement;": "\u220c",
+  "NotRightTriangle;": "\u22eb",
+  "NotRightTriangleBar;": "\u29d0\u0338",
+  "NotRightTriangleEqual;": "\u22ed",
+  "NotSquareSubset;": "\u228f\u0338",
+  "NotSquareSubsetEqual;": "\u22e2",
+  "NotSquareSuperset;": "\u2290\u0338",
+  "NotSquareSupersetEqual;": "\u22e3",
+  "NotSubset;": "\u2282\u20d2",
+  "NotSubsetEqual;": "\u2288",
+  "NotSucceeds;": "\u2281",
+  "NotSucceedsEqual;": "\u2ab0\u0338",
+  "NotSucceedsSlantEqual;": "\u22e1",
+  "NotSucceedsTilde;": "\u227f\u0338",
+  "NotSuperset;": "\u2283\u20d2",
+  "NotSupersetEqual;": "\u2289",
+  "NotTilde;": "\u2241",
+  "NotTildeEqual;": "\u2244",
+  "NotTildeFullEqual;": "\u2247",
+  "NotTildeTilde;": "\u2249",
+  "NotVerticalBar;": "\u2224",
+  "Nscr;": "\u{01d4a9}",
+  "Ntilde": "\xd1",
+  "Ntilde;": "\xd1",
+  "Nu;": "\u039d",
+  "OElig;": "\u0152",
+  "Oacute": "\xd3",
+  "Oacute;": "\xd3",
+  "Ocirc": "\xd4",
+  "Ocirc;": "\xd4",
+  "Ocy;": "\u041e",
+  "Odblac;": "\u0150",
+  "Ofr;": "\u{01d512}",
+  "Ograve": "\xd2",
+  "Ograve;": "\xd2",
+  "Omacr;": "\u014c",
+  "Omega;": "\u03a9",
+  "Omicron;": "\u039f",
+  "Oopf;": "\u{01d546}",
+  "OpenCurlyDoubleQuote;": "\u201c",
+  "OpenCurlyQuote;": "\u2018",
+  "Or;": "\u2a54",
+  "Oscr;": "\u{01d4aa}",
+  "Oslash": "\xd8",
+  "Oslash;": "\xd8",
+  "Otilde": "\xd5",
+  "Otilde;": "\xd5",
+  "Otimes;": "\u2a37",
+  "Ouml": "\xd6",
+  "Ouml;": "\xd6",
+  "OverBar;": "\u203e",
+  "OverBrace;": "\u23de",
+  "OverBracket;": "\u23b4",
+  "OverParenthesis;": "\u23dc",
+  "PartialD;": "\u2202",
+  "Pcy;": "\u041f",
+  "Pfr;": "\u{01d513}",
+  "Phi;": "\u03a6",
+  "Pi;": "\u03a0",
+  "PlusMinus;": "\xb1",
+  "Poincareplane;": "\u210c",
+  "Popf;": "\u2119",
+  "Pr;": "\u2abb",
+  "Precedes;": "\u227a",
+  "PrecedesEqual;": "\u2aaf",
+  "PrecedesSlantEqual;": "\u227c",
+  "PrecedesTilde;": "\u227e",
+  "Prime;": "\u2033",
+  "Product;": "\u220f",
+  "Proportion;": "\u2237",
+  "Proportional;": "\u221d",
+  "Pscr;": "\u{01d4ab}",
+  "Psi;": "\u03a8",
+  "QUOT": "\"",
+  "QUOT;": "\"",
+  "Qfr;": "\u{01d514}",
+  "Qopf;": "\u211a",
+  "Qscr;": "\u{01d4ac}",
+  "RBarr;": "\u2910",
+  "REG": "\xae",
+  "REG;": "\xae",
+  "Racute;": "\u0154",
+  "Rang;": "\u27eb",
+  "Rarr;": "\u21a0",
+  "Rarrtl;": "\u2916",
+  "Rcaron;": "\u0158",
+  "Rcedil;": "\u0156",
+  "Rcy;": "\u0420",
+  "Re;": "\u211c",
+  "ReverseElement;": "\u220b",
+  "ReverseEquilibrium;": "\u21cb",
+  "ReverseUpEquilibrium;": "\u296f",
+  "Rfr;": "\u211c",
+  "Rho;": "\u03a1",
+  "RightAngleBracket;": "\u27e9",
+  "RightArrow;": "\u2192",
+  "RightArrowBar;": "\u21e5",
+  "RightArrowLeftArrow;": "\u21c4",
+  "RightCeiling;": "\u2309",
+  "RightDoubleBracket;": "\u27e7",
+  "RightDownTeeVector;": "\u295d",
+  "RightDownVector;": "\u21c2",
+  "RightDownVectorBar;": "\u2955",
+  "RightFloor;": "\u230b",
+  "RightTee;": "\u22a2",
+  "RightTeeArrow;": "\u21a6",
+  "RightTeeVector;": "\u295b",
+  "RightTriangle;": "\u22b3",
+  "RightTriangleBar;": "\u29d0",
+  "RightTriangleEqual;": "\u22b5",
+  "RightUpDownVector;": "\u294f",
+  "RightUpTeeVector;": "\u295c",
+  "RightUpVector;": "\u21be",
+  "RightUpVectorBar;": "\u2954",
+  "RightVector;": "\u21c0",
+  "RightVectorBar;": "\u2953",
+  "Rightarrow;": "\u21d2",
+  "Ropf;": "\u211d",
+  "RoundImplies;": "\u2970",
+  "Rrightarrow;": "\u21db",
+  "Rscr;": "\u211b",
+  "Rsh;": "\u21b1",
+  "RuleDelayed;": "\u29f4",
+  "SHCHcy;": "\u0429",
+  "SHcy;": "\u0428",
+  "SOFTcy;": "\u042c",
+  "Sacute;": "\u015a",
+  "Sc;": "\u2abc",
+  "Scaron;": "\u0160",
+  "Scedil;": "\u015e",
+  "Scirc;": "\u015c",
+  "Scy;": "\u0421",
+  "Sfr;": "\u{01d516}",
+  "ShortDownArrow;": "\u2193",
+  "ShortLeftArrow;": "\u2190",
+  "ShortRightArrow;": "\u2192",
+  "ShortUpArrow;": "\u2191",
+  "Sigma;": "\u03a3",
+  "SmallCircle;": "\u2218",
+  "Sopf;": "\u{01d54a}",
+  "Sqrt;": "\u221a",
+  "Square;": "\u25a1",
+  "SquareIntersection;": "\u2293",
+  "SquareSubset;": "\u228f",
+  "SquareSubsetEqual;": "\u2291",
+  "SquareSuperset;": "\u2290",
+  "SquareSupersetEqual;": "\u2292",
+  "SquareUnion;": "\u2294",
+  "Sscr;": "\u{01d4ae}",
+  "Star;": "\u22c6",
+  "Sub;": "\u22d0",
+  "Subset;": "\u22d0",
+  "SubsetEqual;": "\u2286",
+  "Succeeds;": "\u227b",
+  "SucceedsEqual;": "\u2ab0",
+  "SucceedsSlantEqual;": "\u227d",
+  "SucceedsTilde;": "\u227f",
+  "SuchThat;": "\u220b",
+  "Sum;": "\u2211",
+  "Sup;": "\u22d1",
+  "Superset;": "\u2283",
+  "SupersetEqual;": "\u2287",
+  "Supset;": "\u22d1",
+  "THORN": "\xde",
+  "THORN;": "\xde",
+  "TRADE;": "\u2122",
+  "TSHcy;": "\u040b",
+  "TScy;": "\u0426",
+  "Tab;": "\t",
+  "Tau;": "\u03a4",
+  "Tcaron;": "\u0164",
+  "Tcedil;": "\u0162",
+  "Tcy;": "\u0422",
+  "Tfr;": "\u{01d517}",
+  "Therefore;": "\u2234",
+  "Theta;": "\u0398",
+  "ThickSpace;": "\u205f\u200a",
+  "ThinSpace;": "\u2009",
+  "Tilde;": "\u223c",
+  "TildeEqual;": "\u2243",
+  "TildeFullEqual;": "\u2245",
+  "TildeTilde;": "\u2248",
+  "Topf;": "\u{01d54b}",
+  "TripleDot;": "\u20db",
+  "Tscr;": "\u{01d4af}",
+  "Tstrok;": "\u0166",
+  "Uacute": "\xda",
+  "Uacute;": "\xda",
+  "Uarr;": "\u219f",
+  "Uarrocir;": "\u2949",
+  "Ubrcy;": "\u040e",
+  "Ubreve;": "\u016c",
+  "Ucirc": "\xdb",
+  "Ucirc;": "\xdb",
+  "Ucy;": "\u0423",
+  "Udblac;": "\u0170",
+  "Ufr;": "\u{01d518}",
+  "Ugrave": "\xd9",
+  "Ugrave;": "\xd9",
+  "Umacr;": "\u016a",
+  "UnderBar;": "_",
+  "UnderBrace;": "\u23df",
+  "UnderBracket;": "\u23b5",
+  "UnderParenthesis;": "\u23dd",
+  "Union;": "\u22c3",
+  "UnionPlus;": "\u228e",
+  "Uogon;": "\u0172",
+  "Uopf;": "\u{01d54c}",
+  "UpArrow;": "\u2191",
+  "UpArrowBar;": "\u2912",
+  "UpArrowDownArrow;": "\u21c5",
+  "UpDownArrow;": "\u2195",
+  "UpEquilibrium;": "\u296e",
+  "UpTee;": "\u22a5",
+  "UpTeeArrow;": "\u21a5",
+  "Uparrow;": "\u21d1",
+  "Updownarrow;": "\u21d5",
+  "UpperLeftArrow;": "\u2196",
+  "UpperRightArrow;": "\u2197",
+  "Upsi;": "\u03d2",
+  "Upsilon;": "\u03a5",
+  "Uring;": "\u016e",
+  "Uscr;": "\u{01d4b0}",
+  "Utilde;": "\u0168",
+  "Uuml": "\xdc",
+  "Uuml;": "\xdc",
+  "VDash;": "\u22ab",
+  "Vbar;": "\u2aeb",
+  "Vcy;": "\u0412",
+  "Vdash;": "\u22a9",
+  "Vdashl;": "\u2ae6",
+  "Vee;": "\u22c1",
+  "Verbar;": "\u2016",
+  "Vert;": "\u2016",
+  "VerticalBar;": "\u2223",
+  "VerticalLine;": "|",
+  "VerticalSeparator;": "\u2758",
+  "VerticalTilde;": "\u2240",
+  "VeryThinSpace;": "\u200a",
+  "Vfr;": "\u{01d519}",
+  "Vopf;": "\u{01d54d}",
+  "Vscr;": "\u{01d4b1}",
+  "Vvdash;": "\u22aa",
+  "Wcirc;": "\u0174",
+  "Wedge;": "\u22c0",
+  "Wfr;": "\u{01d51a}",
+  "Wopf;": "\u{01d54e}",
+  "Wscr;": "\u{01d4b2}",
+  "Xfr;": "\u{01d51b}",
+  "Xi;": "\u039e",
+  "Xopf;": "\u{01d54f}",
+  "Xscr;": "\u{01d4b3}",
+  "YAcy;": "\u042f",
+  "YIcy;": "\u0407",
+  "YUcy;": "\u042e",
+  "Yacute": "\xdd",
+  "Yacute;": "\xdd",
+  "Ycirc;": "\u0176",
+  "Ycy;": "\u042b",
+  "Yfr;": "\u{01d51c}",
+  "Yopf;": "\u{01d550}",
+  "Yscr;": "\u{01d4b4}",
+  "Yuml;": "\u0178",
+  "ZHcy;": "\u0416",
+  "Zacute;": "\u0179",
+  "Zcaron;": "\u017d",
+  "Zcy;": "\u0417",
+  "Zdot;": "\u017b",
+  "ZeroWidthSpace;": "\u200b",
+  "Zeta;": "\u0396",
+  "Zfr;": "\u2128",
+  "Zopf;": "\u2124",
+  "Zscr;": "\u{01d4b5}",
+  "aacute": "\xe1",
+  "aacute;": "\xe1",
+  "abreve;": "\u0103",
+  "ac;": "\u223e",
+  "acE;": "\u223e\u0333",
+  "acd;": "\u223f",
+  "acirc": "\xe2",
+  "acirc;": "\xe2",
+  "acute": "\xb4",
+  "acute;": "\xb4",
+  "acy;": "\u0430",
+  "aelig": "\xe6",
+  "aelig;": "\xe6",
+  "af;": "\u2061",
+  "afr;": "\u{01d51e}",
+  "agrave": "\xe0",
+  "agrave;": "\xe0",
+  "alefsym;": "\u2135",
+  "aleph;": "\u2135",
+  "alpha;": "\u03b1",
+  "amacr;": "\u0101",
+  "amalg;": "\u2a3f",
+  "amp": "&",
+  "amp;": "&",
+  "and;": "\u2227",
+  "andand;": "\u2a55",
+  "andd;": "\u2a5c",
+  "andslope;": "\u2a58",
+  "andv;": "\u2a5a",
+  "ang;": "\u2220",
+  "ange;": "\u29a4",
+  "angle;": "\u2220",
+  "angmsd;": "\u2221",
+  "angmsdaa;": "\u29a8",
+  "angmsdab;": "\u29a9",
+  "angmsdac;": "\u29aa",
+  "angmsdad;": "\u29ab",
+  "angmsdae;": "\u29ac",
+  "angmsdaf;": "\u29ad",
+  "angmsdag;": "\u29ae",
+  "angmsdah;": "\u29af",
+  "angrt;": "\u221f",
+  "angrtvb;": "\u22be",
+  "angrtvbd;": "\u299d",
+  "angsph;": "\u2222",
+  "angst;": "\xc5",
+  "angzarr;": "\u237c",
+  "aogon;": "\u0105",
+  "aopf;": "\u{01d552}",
+  "ap;": "\u2248",
+  "apE;": "\u2a70",
+  "apacir;": "\u2a6f",
+  "ape;": "\u224a",
+  "apid;": "\u224b",
+  "apos;": "'",
+  "approx;": "\u2248",
+  "approxeq;": "\u224a",
+  "aring": "\xe5",
+  "aring;": "\xe5",
+  "ascr;": "\u{01d4b6}",
+  "ast;": "*",
+  "asymp;": "\u2248",
+  "asympeq;": "\u224d",
+  "atilde": "\xe3",
+  "atilde;": "\xe3",
+  "auml": "\xe4",
+  "auml;": "\xe4",
+  "awconint;": "\u2233",
+  "awint;": "\u2a11",
+  "bNot;": "\u2aed",
+  "backcong;": "\u224c",
+  "backepsilon;": "\u03f6",
+  "backprime;": "\u2035",
+  "backsim;": "\u223d",
+  "backsimeq;": "\u22cd",
+  "barvee;": "\u22bd",
+  "barwed;": "\u2305",
+  "barwedge;": "\u2305",
+  "bbrk;": "\u23b5",
+  "bbrktbrk;": "\u23b6",
+  "bcong;": "\u224c",
+  "bcy;": "\u0431",
+  "bdquo;": "\u201e",
+  "becaus;": "\u2235",
+  "because;": "\u2235",
+  "bemptyv;": "\u29b0",
+  "bepsi;": "\u03f6",
+  "bernou;": "\u212c",
+  "beta;": "\u03b2",
+  "beth;": "\u2136",
+  "between;": "\u226c",
+  "bfr;": "\u{01d51f}",
+  "bigcap;": "\u22c2",
+  "bigcirc;": "\u25ef",
+  "bigcup;": "\u22c3",
+  "bigodot;": "\u2a00",
+  "bigoplus;": "\u2a01",
+  "bigotimes;": "\u2a02",
+  "bigsqcup;": "\u2a06",
+  "bigstar;": "\u2605",
+  "bigtriangledown;": "\u25bd",
+  "bigtriangleup;": "\u25b3",
+  "biguplus;": "\u2a04",
+  "bigvee;": "\u22c1",
+  "bigwedge;": "\u22c0",
+  "bkarow;": "\u290d",
+  "blacklozenge;": "\u29eb",
+  "blacksquare;": "\u25aa",
+  "blacktriangle;": "\u25b4",
+  "blacktriangledown;": "\u25be",
+  "blacktriangleleft;": "\u25c2",
+  "blacktriangleright;": "\u25b8",
+  "blank;": "\u2423",
+  "blk12;": "\u2592",
+  "blk14;": "\u2591",
+  "blk34;": "\u2593",
+  "block;": "\u2588",
+  "bne;": "=\u20e5",
+  "bnequiv;": "\u2261\u20e5",
+  "bnot;": "\u2310",
+  "bopf;": "\u{01d553}",
+  "bot;": "\u22a5",
+  "bottom;": "\u22a5",
+  "bowtie;": "\u22c8",
+  "boxDL;": "\u2557",
+  "boxDR;": "\u2554",
+  "boxDl;": "\u2556",
+  "boxDr;": "\u2553",
+  "boxH;": "\u2550",
+  "boxHD;": "\u2566",
+  "boxHU;": "\u2569",
+  "boxHd;": "\u2564",
+  "boxHu;": "\u2567",
+  "boxUL;": "\u255d",
+  "boxUR;": "\u255a",
+  "boxUl;": "\u255c",
+  "boxUr;": "\u2559",
+  "boxV;": "\u2551",
+  "boxVH;": "\u256c",
+  "boxVL;": "\u2563",
+  "boxVR;": "\u2560",
+  "boxVh;": "\u256b",
+  "boxVl;": "\u2562",
+  "boxVr;": "\u255f",
+  "boxbox;": "\u29c9",
+  "boxdL;": "\u2555",
+  "boxdR;": "\u2552",
+  "boxdl;": "\u2510",
+  "boxdr;": "\u250c",
+  "boxh;": "\u2500",
+  "boxhD;": "\u2565",
+  "boxhU;": "\u2568",
+  "boxhd;": "\u252c",
+  "boxhu;": "\u2534",
+  "boxminus;": "\u229f",
+  "boxplus;": "\u229e",
+  "boxtimes;": "\u22a0",
+  "boxuL;": "\u255b",
+  "boxuR;": "\u2558",
+  "boxul;": "\u2518",
+  "boxur;": "\u2514",
+  "boxv;": "\u2502",
+  "boxvH;": "\u256a",
+  "boxvL;": "\u2561",
+  "boxvR;": "\u255e",
+  "boxvh;": "\u253c",
+  "boxvl;": "\u2524",
+  "boxvr;": "\u251c",
+  "bprime;": "\u2035",
+  "breve;": "\u02d8",
+  "brvbar": "\xa6",
+  "brvbar;": "\xa6",
+  "bscr;": "\u{01d4b7}",
+  "bsemi;": "\u204f",
+  "bsim;": "\u223d",
+  "bsime;": "\u22cd",
+  "bsol;": "\\",
+  "bsolb;": "\u29c5",
+  "bsolhsub;": "\u27c8",
+  "bull;": "\u2022",
+  "bullet;": "\u2022",
+  "bump;": "\u224e",
+  "bumpE;": "\u2aae",
+  "bumpe;": "\u224f",
+  "bumpeq;": "\u224f",
+  "cacute;": "\u0107",
+  "cap;": "\u2229",
+  "capand;": "\u2a44",
+  "capbrcup;": "\u2a49",
+  "capcap;": "\u2a4b",
+  "capcup;": "\u2a47",
+  "capdot;": "\u2a40",
+  "caps;": "\u2229\ufe00",
+  "caret;": "\u2041",
+  "caron;": "\u02c7",
+  "ccaps;": "\u2a4d",
+  "ccaron;": "\u010d",
+  "ccedil": "\xe7",
+  "ccedil;": "\xe7",
+  "ccirc;": "\u0109",
+  "ccups;": "\u2a4c",
+  "ccupssm;": "\u2a50",
+  "cdot;": "\u010b",
+  "cedil": "\xb8",
+  "cedil;": "\xb8",
+  "cemptyv;": "\u29b2",
+  "cent": "\xa2",
+  "cent;": "\xa2",
+  "centerdot;": "\xb7",
+  "cfr;": "\u{01d520}",
+  "chcy;": "\u0447",
+  "check;": "\u2713",
+  "checkmark;": "\u2713",
+  "chi;": "\u03c7",
+  "cir;": "\u25cb",
+  "cirE;": "\u29c3",
+  "circ;": "\u02c6",
+  "circeq;": "\u2257",
+  "circlearrowleft;": "\u21ba",
+  "circlearrowright;": "\u21bb",
+  "circledR;": "\xae",
+  "circledS;": "\u24c8",
+  "circledast;": "\u229b",
+  "circledcirc;": "\u229a",
+  "circleddash;": "\u229d",
+  "cire;": "\u2257",
+  "cirfnint;": "\u2a10",
+  "cirmid;": "\u2aef",
+  "cirscir;": "\u29c2",
+  "clubs;": "\u2663",
+  "clubsuit;": "\u2663",
+  "colon;": ":",
+  "colone;": "\u2254",
+  "coloneq;": "\u2254",
+  "comma;": ",",
+  "commat;": "@",
+  "comp;": "\u2201",
+  "compfn;": "\u2218",
+  "complement;": "\u2201",
+  "complexes;": "\u2102",
+  "cong;": "\u2245",
+  "congdot;": "\u2a6d",
+  "conint;": "\u222e",
+  "copf;": "\u{01d554}",
+  "coprod;": "\u2210",
+  "copy": "\xa9",
+  "copy;": "\xa9",
+  "copysr;": "\u2117",
+  "crarr;": "\u21b5",
+  "cross;": "\u2717",
+  "cscr;": "\u{01d4b8}",
+  "csub;": "\u2acf",
+  "csube;": "\u2ad1",
+  "csup;": "\u2ad0",
+  "csupe;": "\u2ad2",
+  "ctdot;": "\u22ef",
+  "cudarrl;": "\u2938",
+  "cudarrr;": "\u2935",
+  "cuepr;": "\u22de",
+  "cuesc;": "\u22df",
+  "cularr;": "\u21b6",
+  "cularrp;": "\u293d",
+  "cup;": "\u222a",
+  "cupbrcap;": "\u2a48",
+  "cupcap;": "\u2a46",
+  "cupcup;": "\u2a4a",
+  "cupdot;": "\u228d",
+  "cupor;": "\u2a45",
+  "cups;": "\u222a\ufe00",
+  "curarr;": "\u21b7",
+  "curarrm;": "\u293c",
+  "curlyeqprec;": "\u22de",
+  "curlyeqsucc;": "\u22df",
+  "curlyvee;": "\u22ce",
+  "curlywedge;": "\u22cf",
+  "curren": "\xa4",
+  "curren;": "\xa4",
+  "curvearrowleft;": "\u21b6",
+  "curvearrowright;": "\u21b7",
+  "cuvee;": "\u22ce",
+  "cuwed;": "\u22cf",
+  "cwconint;": "\u2232",
+  "cwint;": "\u2231",
+  "cylcty;": "\u232d",
+  "dArr;": "\u21d3",
+  "dHar;": "\u2965",
+  "dagger;": "\u2020",
+  "daleth;": "\u2138",
+  "darr;": "\u2193",
+  "dash;": "\u2010",
+  "dashv;": "\u22a3",
+  "dbkarow;": "\u290f",
+  "dblac;": "\u02dd",
+  "dcaron;": "\u010f",
+  "dcy;": "\u0434",
+  "dd;": "\u2146",
+  "ddagger;": "\u2021",
+  "ddarr;": "\u21ca",
+  "ddotseq;": "\u2a77",
+  "deg": "\xb0",
+  "deg;": "\xb0",
+  "delta;": "\u03b4",
+  "demptyv;": "\u29b1",
+  "dfisht;": "\u297f",
+  "dfr;": "\u{01d521}",
+  "dharl;": "\u21c3",
+  "dharr;": "\u21c2",
+  "diam;": "\u22c4",
+  "diamond;": "\u22c4",
+  "diamondsuit;": "\u2666",
+  "diams;": "\u2666",
+  "die;": "\xa8",
+  "digamma;": "\u03dd",
+  "disin;": "\u22f2",
+  "div;": "\xf7",
+  "divide": "\xf7",
+  "divide;": "\xf7",
+  "divideontimes;": "\u22c7",
+  "divonx;": "\u22c7",
+  "djcy;": "\u0452",
+  "dlcorn;": "\u231e",
+  "dlcrop;": "\u230d",
+  "dollar;": "\$",
+  "dopf;": "\u{01d555}",
+  "dot;": "\u02d9",
+  "doteq;": "\u2250",
+  "doteqdot;": "\u2251",
+  "dotminus;": "\u2238",
+  "dotplus;": "\u2214",
+  "dotsquare;": "\u22a1",
+  "doublebarwedge;": "\u2306",
+  "downarrow;": "\u2193",
+  "downdownarrows;": "\u21ca",
+  "downharpoonleft;": "\u21c3",
+  "downharpoonright;": "\u21c2",
+  "drbkarow;": "\u2910",
+  "drcorn;": "\u231f",
+  "drcrop;": "\u230c",
+  "dscr;": "\u{01d4b9}",
+  "dscy;": "\u0455",
+  "dsol;": "\u29f6",
+  "dstrok;": "\u0111",
+  "dtdot;": "\u22f1",
+  "dtri;": "\u25bf",
+  "dtrif;": "\u25be",
+  "duarr;": "\u21f5",
+  "duhar;": "\u296f",
+  "dwangle;": "\u29a6",
+  "dzcy;": "\u045f",
+  "dzigrarr;": "\u27ff",
+  "eDDot;": "\u2a77",
+  "eDot;": "\u2251",
+  "eacute": "\xe9",
+  "eacute;": "\xe9",
+  "easter;": "\u2a6e",
+  "ecaron;": "\u011b",
+  "ecir;": "\u2256",
+  "ecirc": "\xea",
+  "ecirc;": "\xea",
+  "ecolon;": "\u2255",
+  "ecy;": "\u044d",
+  "edot;": "\u0117",
+  "ee;": "\u2147",
+  "efDot;": "\u2252",
+  "efr;": "\u{01d522}",
+  "eg;": "\u2a9a",
+  "egrave": "\xe8",
+  "egrave;": "\xe8",
+  "egs;": "\u2a96",
+  "egsdot;": "\u2a98",
+  "el;": "\u2a99",
+  "elinters;": "\u23e7",
+  "ell;": "\u2113",
+  "els;": "\u2a95",
+  "elsdot;": "\u2a97",
+  "emacr;": "\u0113",
+  "empty;": "\u2205",
+  "emptyset;": "\u2205",
+  "emptyv;": "\u2205",
+  "emsp13;": "\u2004",
+  "emsp14;": "\u2005",
+  "emsp;": "\u2003",
+  "eng;": "\u014b",
+  "ensp;": "\u2002",
+  "eogon;": "\u0119",
+  "eopf;": "\u{01d556}",
+  "epar;": "\u22d5",
+  "eparsl;": "\u29e3",
+  "eplus;": "\u2a71",
+  "epsi;": "\u03b5",
+  "epsilon;": "\u03b5",
+  "epsiv;": "\u03f5",
+  "eqcirc;": "\u2256",
+  "eqcolon;": "\u2255",
+  "eqsim;": "\u2242",
+  "eqslantgtr;": "\u2a96",
+  "eqslantless;": "\u2a95",
+  "equals;": "=",
+  "equest;": "\u225f",
+  "equiv;": "\u2261",
+  "equivDD;": "\u2a78",
+  "eqvparsl;": "\u29e5",
+  "erDot;": "\u2253",
+  "erarr;": "\u2971",
+  "escr;": "\u212f",
+  "esdot;": "\u2250",
+  "esim;": "\u2242",
+  "eta;": "\u03b7",
+  "eth": "\xf0",
+  "eth;": "\xf0",
+  "euml": "\xeb",
+  "euml;": "\xeb",
+  "euro;": "\u20ac",
+  "excl;": "!",
+  "exist;": "\u2203",
+  "expectation;": "\u2130",
+  "exponentiale;": "\u2147",
+  "fallingdotseq;": "\u2252",
+  "fcy;": "\u0444",
+  "female;": "\u2640",
+  "ffilig;": "\ufb03",
+  "fflig;": "\ufb00",
+  "ffllig;": "\ufb04",
+  "ffr;": "\u{01d523}",
+  "filig;": "\ufb01",
+  "fjlig;": "fj",
+  "flat;": "\u266d",
+  "fllig;": "\ufb02",
+  "fltns;": "\u25b1",
+  "fnof;": "\u0192",
+  "fopf;": "\u{01d557}",
+  "forall;": "\u2200",
+  "fork;": "\u22d4",
+  "forkv;": "\u2ad9",
+  "fpartint;": "\u2a0d",
+  "frac12": "\xbd",
+  "frac12;": "\xbd",
+  "frac13;": "\u2153",
+  "frac14": "\xbc",
+  "frac14;": "\xbc",
+  "frac15;": "\u2155",
+  "frac16;": "\u2159",
+  "frac18;": "\u215b",
+  "frac23;": "\u2154",
+  "frac25;": "\u2156",
+  "frac34": "\xbe",
+  "frac34;": "\xbe",
+  "frac35;": "\u2157",
+  "frac38;": "\u215c",
+  "frac45;": "\u2158",
+  "frac56;": "\u215a",
+  "frac58;": "\u215d",
+  "frac78;": "\u215e",
+  "frasl;": "\u2044",
+  "frown;": "\u2322",
+  "fscr;": "\u{01d4bb}",
+  "gE;": "\u2267",
+  "gEl;": "\u2a8c",
+  "gacute;": "\u01f5",
+  "gamma;": "\u03b3",
+  "gammad;": "\u03dd",
+  "gap;": "\u2a86",
+  "gbreve;": "\u011f",
+  "gcirc;": "\u011d",
+  "gcy;": "\u0433",
+  "gdot;": "\u0121",
+  "ge;": "\u2265",
+  "gel;": "\u22db",
+  "geq;": "\u2265",
+  "geqq;": "\u2267",
+  "geqslant;": "\u2a7e",
+  "ges;": "\u2a7e",
+  "gescc;": "\u2aa9",
+  "gesdot;": "\u2a80",
+  "gesdoto;": "\u2a82",
+  "gesdotol;": "\u2a84",
+  "gesl;": "\u22db\ufe00",
+  "gesles;": "\u2a94",
+  "gfr;": "\u{01d524}",
+  "gg;": "\u226b",
+  "ggg;": "\u22d9",
+  "gimel;": "\u2137",
+  "gjcy;": "\u0453",
+  "gl;": "\u2277",
+  "glE;": "\u2a92",
+  "gla;": "\u2aa5",
+  "glj;": "\u2aa4",
+  "gnE;": "\u2269",
+  "gnap;": "\u2a8a",
+  "gnapprox;": "\u2a8a",
+  "gne;": "\u2a88",
+  "gneq;": "\u2a88",
+  "gneqq;": "\u2269",
+  "gnsim;": "\u22e7",
+  "gopf;": "\u{01d558}",
+  "grave;": "`",
+  "gscr;": "\u210a",
+  "gsim;": "\u2273",
+  "gsime;": "\u2a8e",
+  "gsiml;": "\u2a90",
+  "gt": ">",
+  "gt;": ">",
+  "gtcc;": "\u2aa7",
+  "gtcir;": "\u2a7a",
+  "gtdot;": "\u22d7",
+  "gtlPar;": "\u2995",
+  "gtquest;": "\u2a7c",
+  "gtrapprox;": "\u2a86",
+  "gtrarr;": "\u2978",
+  "gtrdot;": "\u22d7",
+  "gtreqless;": "\u22db",
+  "gtreqqless;": "\u2a8c",
+  "gtrless;": "\u2277",
+  "gtrsim;": "\u2273",
+  "gvertneqq;": "\u2269\ufe00",
+  "gvnE;": "\u2269\ufe00",
+  "hArr;": "\u21d4",
+  "hairsp;": "\u200a",
+  "half;": "\xbd",
+  "hamilt;": "\u210b",
+  "hardcy;": "\u044a",
+  "harr;": "\u2194",
+  "harrcir;": "\u2948",
+  "harrw;": "\u21ad",
+  "hbar;": "\u210f",
+  "hcirc;": "\u0125",
+  "hearts;": "\u2665",
+  "heartsuit;": "\u2665",
+  "hellip;": "\u2026",
+  "hercon;": "\u22b9",
+  "hfr;": "\u{01d525}",
+  "hksearow;": "\u2925",
+  "hkswarow;": "\u2926",
+  "hoarr;": "\u21ff",
+  "homtht;": "\u223b",
+  "hookleftarrow;": "\u21a9",
+  "hookrightarrow;": "\u21aa",
+  "hopf;": "\u{01d559}",
+  "horbar;": "\u2015",
+  "hscr;": "\u{01d4bd}",
+  "hslash;": "\u210f",
+  "hstrok;": "\u0127",
+  "hybull;": "\u2043",
+  "hyphen;": "\u2010",
+  "iacute": "\xed",
+  "iacute;": "\xed",
+  "ic;": "\u2063",
+  "icirc": "\xee",
+  "icirc;": "\xee",
+  "icy;": "\u0438",
+  "iecy;": "\u0435",
+  "iexcl": "\xa1",
+  "iexcl;": "\xa1",
+  "iff;": "\u21d4",
+  "ifr;": "\u{01d526}",
+  "igrave": "\xec",
+  "igrave;": "\xec",
+  "ii;": "\u2148",
+  "iiiint;": "\u2a0c",
+  "iiint;": "\u222d",
+  "iinfin;": "\u29dc",
+  "iiota;": "\u2129",
+  "ijlig;": "\u0133",
+  "imacr;": "\u012b",
+  "image;": "\u2111",
+  "imagline;": "\u2110",
+  "imagpart;": "\u2111",
+  "imath;": "\u0131",
+  "imof;": "\u22b7",
+  "imped;": "\u01b5",
+  "in;": "\u2208",
+  "incare;": "\u2105",
+  "infin;": "\u221e",
+  "infintie;": "\u29dd",
+  "inodot;": "\u0131",
+  "int;": "\u222b",
+  "intcal;": "\u22ba",
+  "integers;": "\u2124",
+  "intercal;": "\u22ba",
+  "intlarhk;": "\u2a17",
+  "intprod;": "\u2a3c",
+  "iocy;": "\u0451",
+  "iogon;": "\u012f",
+  "iopf;": "\u{01d55a}",
+  "iota;": "\u03b9",
+  "iprod;": "\u2a3c",
+  "iquest": "\xbf",
+  "iquest;": "\xbf",
+  "iscr;": "\u{01d4be}",
+  "isin;": "\u2208",
+  "isinE;": "\u22f9",
+  "isindot;": "\u22f5",
+  "isins;": "\u22f4",
+  "isinsv;": "\u22f3",
+  "isinv;": "\u2208",
+  "it;": "\u2062",
+  "itilde;": "\u0129",
+  "iukcy;": "\u0456",
+  "iuml": "\xef",
+  "iuml;": "\xef",
+  "jcirc;": "\u0135",
+  "jcy;": "\u0439",
+  "jfr;": "\u{01d527}",
+  "jmath;": "\u0237",
+  "jopf;": "\u{01d55b}",
+  "jscr;": "\u{01d4bf}",
+  "jsercy;": "\u0458",
+  "jukcy;": "\u0454",
+  "kappa;": "\u03ba",
+  "kappav;": "\u03f0",
+  "kcedil;": "\u0137",
+  "kcy;": "\u043a",
+  "kfr;": "\u{01d528}",
+  "kgreen;": "\u0138",
+  "khcy;": "\u0445",
+  "kjcy;": "\u045c",
+  "kopf;": "\u{01d55c}",
+  "kscr;": "\u{01d4c0}",
+  "lAarr;": "\u21da",
+  "lArr;": "\u21d0",
+  "lAtail;": "\u291b",
+  "lBarr;": "\u290e",
+  "lE;": "\u2266",
+  "lEg;": "\u2a8b",
+  "lHar;": "\u2962",
+  "lacute;": "\u013a",
+  "laemptyv;": "\u29b4",
+  "lagran;": "\u2112",
+  "lambda;": "\u03bb",
+  "lang;": "\u27e8",
+  "langd;": "\u2991",
+  "langle;": "\u27e8",
+  "lap;": "\u2a85",
+  "laquo": "\xab",
+  "laquo;": "\xab",
+  "larr;": "\u2190",
+  "larrb;": "\u21e4",
+  "larrbfs;": "\u291f",
+  "larrfs;": "\u291d",
+  "larrhk;": "\u21a9",
+  "larrlp;": "\u21ab",
+  "larrpl;": "\u2939",
+  "larrsim;": "\u2973",
+  "larrtl;": "\u21a2",
+  "lat;": "\u2aab",
+  "latail;": "\u2919",
+  "late;": "\u2aad",
+  "lates;": "\u2aad\ufe00",
+  "lbarr;": "\u290c",
+  "lbbrk;": "\u2772",
+  "lbrace;": "{",
+  "lbrack;": "[",
+  "lbrke;": "\u298b",
+  "lbrksld;": "\u298f",
+  "lbrkslu;": "\u298d",
+  "lcaron;": "\u013e",
+  "lcedil;": "\u013c",
+  "lceil;": "\u2308",
+  "lcub;": "{",
+  "lcy;": "\u043b",
+  "ldca;": "\u2936",
+  "ldquo;": "\u201c",
+  "ldquor;": "\u201e",
+  "ldrdhar;": "\u2967",
+  "ldrushar;": "\u294b",
+  "ldsh;": "\u21b2",
+  "le;": "\u2264",
+  "leftarrow;": "\u2190",
+  "leftarrowtail;": "\u21a2",
+  "leftharpoondown;": "\u21bd",
+  "leftharpoonup;": "\u21bc",
+  "leftleftarrows;": "\u21c7",
+  "leftrightarrow;": "\u2194",
+  "leftrightarrows;": "\u21c6",
+  "leftrightharpoons;": "\u21cb",
+  "leftrightsquigarrow;": "\u21ad",
+  "leftthreetimes;": "\u22cb",
+  "leg;": "\u22da",
+  "leq;": "\u2264",
+  "leqq;": "\u2266",
+  "leqslant;": "\u2a7d",
+  "les;": "\u2a7d",
+  "lescc;": "\u2aa8",
+  "lesdot;": "\u2a7f",
+  "lesdoto;": "\u2a81",
+  "lesdotor;": "\u2a83",
+  "lesg;": "\u22da\ufe00",
+  "lesges;": "\u2a93",
+  "lessapprox;": "\u2a85",
+  "lessdot;": "\u22d6",
+  "lesseqgtr;": "\u22da",
+  "lesseqqgtr;": "\u2a8b",
+  "lessgtr;": "\u2276",
+  "lesssim;": "\u2272",
+  "lfisht;": "\u297c",
+  "lfloor;": "\u230a",
+  "lfr;": "\u{01d529}",
+  "lg;": "\u2276",
+  "lgE;": "\u2a91",
+  "lhard;": "\u21bd",
+  "lharu;": "\u21bc",
+  "lharul;": "\u296a",
+  "lhblk;": "\u2584",
+  "ljcy;": "\u0459",
+  "ll;": "\u226a",
+  "llarr;": "\u21c7",
+  "llcorner;": "\u231e",
+  "llhard;": "\u296b",
+  "lltri;": "\u25fa",
+  "lmidot;": "\u0140",
+  "lmoust;": "\u23b0",
+  "lmoustache;": "\u23b0",
+  "lnE;": "\u2268",
+  "lnap;": "\u2a89",
+  "lnapprox;": "\u2a89",
+  "lne;": "\u2a87",
+  "lneq;": "\u2a87",
+  "lneqq;": "\u2268",
+  "lnsim;": "\u22e6",
+  "loang;": "\u27ec",
+  "loarr;": "\u21fd",
+  "lobrk;": "\u27e6",
+  "longleftarrow;": "\u27f5",
+  "longleftrightarrow;": "\u27f7",
+  "longmapsto;": "\u27fc",
+  "longrightarrow;": "\u27f6",
+  "looparrowleft;": "\u21ab",
+  "looparrowright;": "\u21ac",
+  "lopar;": "\u2985",
+  "lopf;": "\u{01d55d}",
+  "loplus;": "\u2a2d",
+  "lotimes;": "\u2a34",
+  "lowast;": "\u2217",
+  "lowbar;": "_",
+  "loz;": "\u25ca",
+  "lozenge;": "\u25ca",
+  "lozf;": "\u29eb",
+  "lpar;": "(",
+  "lparlt;": "\u2993",
+  "lrarr;": "\u21c6",
+  "lrcorner;": "\u231f",
+  "lrhar;": "\u21cb",
+  "lrhard;": "\u296d",
+  "lrm;": "\u200e",
+  "lrtri;": "\u22bf",
+  "lsaquo;": "\u2039",
+  "lscr;": "\u{01d4c1}",
+  "lsh;": "\u21b0",
+  "lsim;": "\u2272",
+  "lsime;": "\u2a8d",
+  "lsimg;": "\u2a8f",
+  "lsqb;": "[",
+  "lsquo;": "\u2018",
+  "lsquor;": "\u201a",
+  "lstrok;": "\u0142",
+  "lt": "<",
+  "lt;": "<",
+  "ltcc;": "\u2aa6",
+  "ltcir;": "\u2a79",
+  "ltdot;": "\u22d6",
+  "lthree;": "\u22cb",
+  "ltimes;": "\u22c9",
+  "ltlarr;": "\u2976",
+  "ltquest;": "\u2a7b",
+  "ltrPar;": "\u2996",
+  "ltri;": "\u25c3",
+  "ltrie;": "\u22b4",
+  "ltrif;": "\u25c2",
+  "lurdshar;": "\u294a",
+  "luruhar;": "\u2966",
+  "lvertneqq;": "\u2268\ufe00",
+  "lvnE;": "\u2268\ufe00",
+  "mDDot;": "\u223a",
+  "macr": "\xaf",
+  "macr;": "\xaf",
+  "male;": "\u2642",
+  "malt;": "\u2720",
+  "maltese;": "\u2720",
+  "map;": "\u21a6",
+  "mapsto;": "\u21a6",
+  "mapstodown;": "\u21a7",
+  "mapstoleft;": "\u21a4",
+  "mapstoup;": "\u21a5",
+  "marker;": "\u25ae",
+  "mcomma;": "\u2a29",
+  "mcy;": "\u043c",
+  "mdash;": "\u2014",
+  "measuredangle;": "\u2221",
+  "mfr;": "\u{01d52a}",
+  "mho;": "\u2127",
+  "micro": "\xb5",
+  "micro;": "\xb5",
+  "mid;": "\u2223",
+  "midast;": "*",
+  "midcir;": "\u2af0",
+  "middot": "\xb7",
+  "middot;": "\xb7",
+  "minus;": "\u2212",
+  "minusb;": "\u229f",
+  "minusd;": "\u2238",
+  "minusdu;": "\u2a2a",
+  "mlcp;": "\u2adb",
+  "mldr;": "\u2026",
+  "mnplus;": "\u2213",
+  "models;": "\u22a7",
+  "mopf;": "\u{01d55e}",
+  "mp;": "\u2213",
+  "mscr;": "\u{01d4c2}",
+  "mstpos;": "\u223e",
+  "mu;": "\u03bc",
+  "multimap;": "\u22b8",
+  "mumap;": "\u22b8",
+  "nGg;": "\u22d9\u0338",
+  "nGt;": "\u226b\u20d2",
+  "nGtv;": "\u226b\u0338",
+  "nLeftarrow;": "\u21cd",
+  "nLeftrightarrow;": "\u21ce",
+  "nLl;": "\u22d8\u0338",
+  "nLt;": "\u226a\u20d2",
+  "nLtv;": "\u226a\u0338",
+  "nRightarrow;": "\u21cf",
+  "nVDash;": "\u22af",
+  "nVdash;": "\u22ae",
+  "nabla;": "\u2207",
+  "nacute;": "\u0144",
+  "nang;": "\u2220\u20d2",
+  "nap;": "\u2249",
+  "napE;": "\u2a70\u0338",
+  "napid;": "\u224b\u0338",
+  "napos;": "\u0149",
+  "napprox;": "\u2249",
+  "natur;": "\u266e",
+  "natural;": "\u266e",
+  "naturals;": "\u2115",
+  "nbsp": "\xa0",
+  "nbsp;": "\xa0",
+  "nbump;": "\u224e\u0338",
+  "nbumpe;": "\u224f\u0338",
+  "ncap;": "\u2a43",
+  "ncaron;": "\u0148",
+  "ncedil;": "\u0146",
+  "ncong;": "\u2247",
+  "ncongdot;": "\u2a6d\u0338",
+  "ncup;": "\u2a42",
+  "ncy;": "\u043d",
+  "ndash;": "\u2013",
+  "ne;": "\u2260",
+  "neArr;": "\u21d7",
+  "nearhk;": "\u2924",
+  "nearr;": "\u2197",
+  "nearrow;": "\u2197",
+  "nedot;": "\u2250\u0338",
+  "nequiv;": "\u2262",
+  "nesear;": "\u2928",
+  "nesim;": "\u2242\u0338",
+  "nexist;": "\u2204",
+  "nexists;": "\u2204",
+  "nfr;": "\u{01d52b}",
+  "ngE;": "\u2267\u0338",
+  "nge;": "\u2271",
+  "ngeq;": "\u2271",
+  "ngeqq;": "\u2267\u0338",
+  "ngeqslant;": "\u2a7e\u0338",
+  "nges;": "\u2a7e\u0338",
+  "ngsim;": "\u2275",
+  "ngt;": "\u226f",
+  "ngtr;": "\u226f",
+  "nhArr;": "\u21ce",
+  "nharr;": "\u21ae",
+  "nhpar;": "\u2af2",
+  "ni;": "\u220b",
+  "nis;": "\u22fc",
+  "nisd;": "\u22fa",
+  "niv;": "\u220b",
+  "njcy;": "\u045a",
+  "nlArr;": "\u21cd",
+  "nlE;": "\u2266\u0338",
+  "nlarr;": "\u219a",
+  "nldr;": "\u2025",
+  "nle;": "\u2270",
+  "nleftarrow;": "\u219a",
+  "nleftrightarrow;": "\u21ae",
+  "nleq;": "\u2270",
+  "nleqq;": "\u2266\u0338",
+  "nleqslant;": "\u2a7d\u0338",
+  "nles;": "\u2a7d\u0338",
+  "nless;": "\u226e",
+  "nlsim;": "\u2274",
+  "nlt;": "\u226e",
+  "nltri;": "\u22ea",
+  "nltrie;": "\u22ec",
+  "nmid;": "\u2224",
+  "nopf;": "\u{01d55f}",
+  "not": "\xac",
+  "not;": "\xac",
+  "notin;": "\u2209",
+  "notinE;": "\u22f9\u0338",
+  "notindot;": "\u22f5\u0338",
+  "notinva;": "\u2209",
+  "notinvb;": "\u22f7",
+  "notinvc;": "\u22f6",
+  "notni;": "\u220c",
+  "notniva;": "\u220c",
+  "notnivb;": "\u22fe",
+  "notnivc;": "\u22fd",
+  "npar;": "\u2226",
+  "nparallel;": "\u2226",
+  "nparsl;": "\u2afd\u20e5",
+  "npart;": "\u2202\u0338",
+  "npolint;": "\u2a14",
+  "npr;": "\u2280",
+  "nprcue;": "\u22e0",
+  "npre;": "\u2aaf\u0338",
+  "nprec;": "\u2280",
+  "npreceq;": "\u2aaf\u0338",
+  "nrArr;": "\u21cf",
+  "nrarr;": "\u219b",
+  "nrarrc;": "\u2933\u0338",
+  "nrarrw;": "\u219d\u0338",
+  "nrightarrow;": "\u219b",
+  "nrtri;": "\u22eb",
+  "nrtrie;": "\u22ed",
+  "nsc;": "\u2281",
+  "nsccue;": "\u22e1",
+  "nsce;": "\u2ab0\u0338",
+  "nscr;": "\u{01d4c3}",
+  "nshortmid;": "\u2224",
+  "nshortparallel;": "\u2226",
+  "nsim;": "\u2241",
+  "nsime;": "\u2244",
+  "nsimeq;": "\u2244",
+  "nsmid;": "\u2224",
+  "nspar;": "\u2226",
+  "nsqsube;": "\u22e2",
+  "nsqsupe;": "\u22e3",
+  "nsub;": "\u2284",
+  "nsubE;": "\u2ac5\u0338",
+  "nsube;": "\u2288",
+  "nsubset;": "\u2282\u20d2",
+  "nsubseteq;": "\u2288",
+  "nsubseteqq;": "\u2ac5\u0338",
+  "nsucc;": "\u2281",
+  "nsucceq;": "\u2ab0\u0338",
+  "nsup;": "\u2285",
+  "nsupE;": "\u2ac6\u0338",
+  "nsupe;": "\u2289",
+  "nsupset;": "\u2283\u20d2",
+  "nsupseteq;": "\u2289",
+  "nsupseteqq;": "\u2ac6\u0338",
+  "ntgl;": "\u2279",
+  "ntilde": "\xf1",
+  "ntilde;": "\xf1",
+  "ntlg;": "\u2278",
+  "ntriangleleft;": "\u22ea",
+  "ntrianglelefteq;": "\u22ec",
+  "ntriangleright;": "\u22eb",
+  "ntrianglerighteq;": "\u22ed",
+  "nu;": "\u03bd",
+  "num;": "#",
+  "numero;": "\u2116",
+  "numsp;": "\u2007",
+  "nvDash;": "\u22ad",
+  "nvHarr;": "\u2904",
+  "nvap;": "\u224d\u20d2",
+  "nvdash;": "\u22ac",
+  "nvge;": "\u2265\u20d2",
+  "nvgt;": ">\u20d2",
+  "nvinfin;": "\u29de",
+  "nvlArr;": "\u2902",
+  "nvle;": "\u2264\u20d2",
+  "nvlt;": "<\u20d2",
+  "nvltrie;": "\u22b4\u20d2",
+  "nvrArr;": "\u2903",
+  "nvrtrie;": "\u22b5\u20d2",
+  "nvsim;": "\u223c\u20d2",
+  "nwArr;": "\u21d6",
+  "nwarhk;": "\u2923",
+  "nwarr;": "\u2196",
+  "nwarrow;": "\u2196",
+  "nwnear;": "\u2927",
+  "oS;": "\u24c8",
+  "oacute": "\xf3",
+  "oacute;": "\xf3",
+  "oast;": "\u229b",
+  "ocir;": "\u229a",
+  "ocirc": "\xf4",
+  "ocirc;": "\xf4",
+  "ocy;": "\u043e",
+  "odash;": "\u229d",
+  "odblac;": "\u0151",
+  "odiv;": "\u2a38",
+  "odot;": "\u2299",
+  "odsold;": "\u29bc",
+  "oelig;": "\u0153",
+  "ofcir;": "\u29bf",
+  "ofr;": "\u{01d52c}",
+  "ogon;": "\u02db",
+  "ograve": "\xf2",
+  "ograve;": "\xf2",
+  "ogt;": "\u29c1",
+  "ohbar;": "\u29b5",
+  "ohm;": "\u03a9",
+  "oint;": "\u222e",
+  "olarr;": "\u21ba",
+  "olcir;": "\u29be",
+  "olcross;": "\u29bb",
+  "oline;": "\u203e",
+  "olt;": "\u29c0",
+  "omacr;": "\u014d",
+  "omega;": "\u03c9",
+  "omicron;": "\u03bf",
+  "omid;": "\u29b6",
+  "ominus;": "\u2296",
+  "oopf;": "\u{01d560}",
+  "opar;": "\u29b7",
+  "operp;": "\u29b9",
+  "oplus;": "\u2295",
+  "or;": "\u2228",
+  "orarr;": "\u21bb",
+  "ord;": "\u2a5d",
+  "order;": "\u2134",
+  "orderof;": "\u2134",
+  "ordf": "\xaa",
+  "ordf;": "\xaa",
+  "ordm": "\xba",
+  "ordm;": "\xba",
+  "origof;": "\u22b6",
+  "oror;": "\u2a56",
+  "orslope;": "\u2a57",
+  "orv;": "\u2a5b",
+  "oscr;": "\u2134",
+  "oslash": "\xf8",
+  "oslash;": "\xf8",
+  "osol;": "\u2298",
+  "otilde": "\xf5",
+  "otilde;": "\xf5",
+  "otimes;": "\u2297",
+  "otimesas;": "\u2a36",
+  "ouml": "\xf6",
+  "ouml;": "\xf6",
+  "ovbar;": "\u233d",
+  "par;": "\u2225",
+  "para": "\xb6",
+  "para;": "\xb6",
+  "parallel;": "\u2225",
+  "parsim;": "\u2af3",
+  "parsl;": "\u2afd",
+  "part;": "\u2202",
+  "pcy;": "\u043f",
+  "percnt;": "%",
+  "period;": ".",
+  "permil;": "\u2030",
+  "perp;": "\u22a5",
+  "pertenk;": "\u2031",
+  "pfr;": "\u{01d52d}",
+  "phi;": "\u03c6",
+  "phiv;": "\u03d5",
+  "phmmat;": "\u2133",
+  "phone;": "\u260e",
+  "pi;": "\u03c0",
+  "pitchfork;": "\u22d4",
+  "piv;": "\u03d6",
+  "planck;": "\u210f",
+  "planckh;": "\u210e",
+  "plankv;": "\u210f",
+  "plus;": "+",
+  "plusacir;": "\u2a23",
+  "plusb;": "\u229e",
+  "pluscir;": "\u2a22",
+  "plusdo;": "\u2214",
+  "plusdu;": "\u2a25",
+  "pluse;": "\u2a72",
+  "plusmn": "\xb1",
+  "plusmn;": "\xb1",
+  "plussim;": "\u2a26",
+  "plustwo;": "\u2a27",
+  "pm;": "\xb1",
+  "pointint;": "\u2a15",
+  "popf;": "\u{01d561}",
+  "pound": "\xa3",
+  "pound;": "\xa3",
+  "pr;": "\u227a",
+  "prE;": "\u2ab3",
+  "prap;": "\u2ab7",
+  "prcue;": "\u227c",
+  "pre;": "\u2aaf",
+  "prec;": "\u227a",
+  "precapprox;": "\u2ab7",
+  "preccurlyeq;": "\u227c",
+  "preceq;": "\u2aaf",
+  "precnapprox;": "\u2ab9",
+  "precneqq;": "\u2ab5",
+  "precnsim;": "\u22e8",
+  "precsim;": "\u227e",
+  "prime;": "\u2032",
+  "primes;": "\u2119",
+  "prnE;": "\u2ab5",
+  "prnap;": "\u2ab9",
+  "prnsim;": "\u22e8",
+  "prod;": "\u220f",
+  "profalar;": "\u232e",
+  "profline;": "\u2312",
+  "profsurf;": "\u2313",
+  "prop;": "\u221d",
+  "propto;": "\u221d",
+  "prsim;": "\u227e",
+  "prurel;": "\u22b0",
+  "pscr;": "\u{01d4c5}",
+  "psi;": "\u03c8",
+  "puncsp;": "\u2008",
+  "qfr;": "\u{01d52e}",
+  "qint;": "\u2a0c",
+  "qopf;": "\u{01d562}",
+  "qprime;": "\u2057",
+  "qscr;": "\u{01d4c6}",
+  "quaternions;": "\u210d",
+  "quatint;": "\u2a16",
+  "quest;": "?",
+  "questeq;": "\u225f",
+  "quot": "\"",
+  "quot;": "\"",
+  "rAarr;": "\u21db",
+  "rArr;": "\u21d2",
+  "rAtail;": "\u291c",
+  "rBarr;": "\u290f",
+  "rHar;": "\u2964",
+  "race;": "\u223d\u0331",
+  "racute;": "\u0155",
+  "radic;": "\u221a",
+  "raemptyv;": "\u29b3",
+  "rang;": "\u27e9",
+  "rangd;": "\u2992",
+  "range;": "\u29a5",
+  "rangle;": "\u27e9",
+  "raquo": "\xbb",
+  "raquo;": "\xbb",
+  "rarr;": "\u2192",
+  "rarrap;": "\u2975",
+  "rarrb;": "\u21e5",
+  "rarrbfs;": "\u2920",
+  "rarrc;": "\u2933",
+  "rarrfs;": "\u291e",
+  "rarrhk;": "\u21aa",
+  "rarrlp;": "\u21ac",
+  "rarrpl;": "\u2945",
+  "rarrsim;": "\u2974",
+  "rarrtl;": "\u21a3",
+  "rarrw;": "\u219d",
+  "ratail;": "\u291a",
+  "ratio;": "\u2236",
+  "rationals;": "\u211a",
+  "rbarr;": "\u290d",
+  "rbbrk;": "\u2773",
+  "rbrace;": "}",
+  "rbrack;": "]",
+  "rbrke;": "\u298c",
+  "rbrksld;": "\u298e",
+  "rbrkslu;": "\u2990",
+  "rcaron;": "\u0159",
+  "rcedil;": "\u0157",
+  "rceil;": "\u2309",
+  "rcub;": "}",
+  "rcy;": "\u0440",
+  "rdca;": "\u2937",
+  "rdldhar;": "\u2969",
+  "rdquo;": "\u201d",
+  "rdquor;": "\u201d",
+  "rdsh;": "\u21b3",
+  "real;": "\u211c",
+  "realine;": "\u211b",
+  "realpart;": "\u211c",
+  "reals;": "\u211d",
+  "rect;": "\u25ad",
+  "reg": "\xae",
+  "reg;": "\xae",
+  "rfisht;": "\u297d",
+  "rfloor;": "\u230b",
+  "rfr;": "\u{01d52f}",
+  "rhard;": "\u21c1",
+  "rharu;": "\u21c0",
+  "rharul;": "\u296c",
+  "rho;": "\u03c1",
+  "rhov;": "\u03f1",
+  "rightarrow;": "\u2192",
+  "rightarrowtail;": "\u21a3",
+  "rightharpoondown;": "\u21c1",
+  "rightharpoonup;": "\u21c0",
+  "rightleftarrows;": "\u21c4",
+  "rightleftharpoons;": "\u21cc",
+  "rightrightarrows;": "\u21c9",
+  "rightsquigarrow;": "\u219d",
+  "rightthreetimes;": "\u22cc",
+  "ring;": "\u02da",
+  "risingdotseq;": "\u2253",
+  "rlarr;": "\u21c4",
+  "rlhar;": "\u21cc",
+  "rlm;": "\u200f",
+  "rmoust;": "\u23b1",
+  "rmoustache;": "\u23b1",
+  "rnmid;": "\u2aee",
+  "roang;": "\u27ed",
+  "roarr;": "\u21fe",
+  "robrk;": "\u27e7",
+  "ropar;": "\u2986",
+  "ropf;": "\u{01d563}",
+  "roplus;": "\u2a2e",
+  "rotimes;": "\u2a35",
+  "rpar;": ")",
+  "rpargt;": "\u2994",
+  "rppolint;": "\u2a12",
+  "rrarr;": "\u21c9",
+  "rsaquo;": "\u203a",
+  "rscr;": "\u{01d4c7}",
+  "rsh;": "\u21b1",
+  "rsqb;": "]",
+  "rsquo;": "\u2019",
+  "rsquor;": "\u2019",
+  "rthree;": "\u22cc",
+  "rtimes;": "\u22ca",
+  "rtri;": "\u25b9",
+  "rtrie;": "\u22b5",
+  "rtrif;": "\u25b8",
+  "rtriltri;": "\u29ce",
+  "ruluhar;": "\u2968",
+  "rx;": "\u211e",
+  "sacute;": "\u015b",
+  "sbquo;": "\u201a",
+  "sc;": "\u227b",
+  "scE;": "\u2ab4",
+  "scap;": "\u2ab8",
+  "scaron;": "\u0161",
+  "sccue;": "\u227d",
+  "sce;": "\u2ab0",
+  "scedil;": "\u015f",
+  "scirc;": "\u015d",
+  "scnE;": "\u2ab6",
+  "scnap;": "\u2aba",
+  "scnsim;": "\u22e9",
+  "scpolint;": "\u2a13",
+  "scsim;": "\u227f",
+  "scy;": "\u0441",
+  "sdot;": "\u22c5",
+  "sdotb;": "\u22a1",
+  "sdote;": "\u2a66",
+  "seArr;": "\u21d8",
+  "searhk;": "\u2925",
+  "searr;": "\u2198",
+  "searrow;": "\u2198",
+  "sect": "\xa7",
+  "sect;": "\xa7",
+  "semi;": ";",
+  "seswar;": "\u2929",
+  "setminus;": "\u2216",
+  "setmn;": "\u2216",
+  "sext;": "\u2736",
+  "sfr;": "\u{01d530}",
+  "sfrown;": "\u2322",
+  "sharp;": "\u266f",
+  "shchcy;": "\u0449",
+  "shcy;": "\u0448",
+  "shortmid;": "\u2223",
+  "shortparallel;": "\u2225",
+  "shy": "\xad",
+  "shy;": "\xad",
+  "sigma;": "\u03c3",
+  "sigmaf;": "\u03c2",
+  "sigmav;": "\u03c2",
+  "sim;": "\u223c",
+  "simdot;": "\u2a6a",
+  "sime;": "\u2243",
+  "simeq;": "\u2243",
+  "simg;": "\u2a9e",
+  "simgE;": "\u2aa0",
+  "siml;": "\u2a9d",
+  "simlE;": "\u2a9f",
+  "simne;": "\u2246",
+  "simplus;": "\u2a24",
+  "simrarr;": "\u2972",
+  "slarr;": "\u2190",
+  "smallsetminus;": "\u2216",
+  "smashp;": "\u2a33",
+  "smeparsl;": "\u29e4",
+  "smid;": "\u2223",
+  "smile;": "\u2323",
+  "smt;": "\u2aaa",
+  "smte;": "\u2aac",
+  "smtes;": "\u2aac\ufe00",
+  "softcy;": "\u044c",
+  "sol;": "/",
+  "solb;": "\u29c4",
+  "solbar;": "\u233f",
+  "sopf;": "\u{01d564}",
+  "spades;": "\u2660",
+  "spadesuit;": "\u2660",
+  "spar;": "\u2225",
+  "sqcap;": "\u2293",
+  "sqcaps;": "\u2293\ufe00",
+  "sqcup;": "\u2294",
+  "sqcups;": "\u2294\ufe00",
+  "sqsub;": "\u228f",
+  "sqsube;": "\u2291",
+  "sqsubset;": "\u228f",
+  "sqsubseteq;": "\u2291",
+  "sqsup;": "\u2290",
+  "sqsupe;": "\u2292",
+  "sqsupset;": "\u2290",
+  "sqsupseteq;": "\u2292",
+  "squ;": "\u25a1",
+  "square;": "\u25a1",
+  "squarf;": "\u25aa",
+  "squf;": "\u25aa",
+  "srarr;": "\u2192",
+  "sscr;": "\u{01d4c8}",
+  "ssetmn;": "\u2216",
+  "ssmile;": "\u2323",
+  "sstarf;": "\u22c6",
+  "star;": "\u2606",
+  "starf;": "\u2605",
+  "straightepsilon;": "\u03f5",
+  "straightphi;": "\u03d5",
+  "strns;": "\xaf",
+  "sub;": "\u2282",
+  "subE;": "\u2ac5",
+  "subdot;": "\u2abd",
+  "sube;": "\u2286",
+  "subedot;": "\u2ac3",
+  "submult;": "\u2ac1",
+  "subnE;": "\u2acb",
+  "subne;": "\u228a",
+  "subplus;": "\u2abf",
+  "subrarr;": "\u2979",
+  "subset;": "\u2282",
+  "subseteq;": "\u2286",
+  "subseteqq;": "\u2ac5",
+  "subsetneq;": "\u228a",
+  "subsetneqq;": "\u2acb",
+  "subsim;": "\u2ac7",
+  "subsub;": "\u2ad5",
+  "subsup;": "\u2ad3",
+  "succ;": "\u227b",
+  "succapprox;": "\u2ab8",
+  "succcurlyeq;": "\u227d",
+  "succeq;": "\u2ab0",
+  "succnapprox;": "\u2aba",
+  "succneqq;": "\u2ab6",
+  "succnsim;": "\u22e9",
+  "succsim;": "\u227f",
+  "sum;": "\u2211",
+  "sung;": "\u266a",
+  "sup1": "\xb9",
+  "sup1;": "\xb9",
+  "sup2": "\xb2",
+  "sup2;": "\xb2",
+  "sup3": "\xb3",
+  "sup3;": "\xb3",
+  "sup;": "\u2283",
+  "supE;": "\u2ac6",
+  "supdot;": "\u2abe",
+  "supdsub;": "\u2ad8",
+  "supe;": "\u2287",
+  "supedot;": "\u2ac4",
+  "suphsol;": "\u27c9",
+  "suphsub;": "\u2ad7",
+  "suplarr;": "\u297b",
+  "supmult;": "\u2ac2",
+  "supnE;": "\u2acc",
+  "supne;": "\u228b",
+  "supplus;": "\u2ac0",
+  "supset;": "\u2283",
+  "supseteq;": "\u2287",
+  "supseteqq;": "\u2ac6",
+  "supsetneq;": "\u228b",
+  "supsetneqq;": "\u2acc",
+  "supsim;": "\u2ac8",
+  "supsub;": "\u2ad4",
+  "supsup;": "\u2ad6",
+  "swArr;": "\u21d9",
+  "swarhk;": "\u2926",
+  "swarr;": "\u2199",
+  "swarrow;": "\u2199",
+  "swnwar;": "\u292a",
+  "szlig": "\xdf",
+  "szlig;": "\xdf",
+  "target;": "\u2316",
+  "tau;": "\u03c4",
+  "tbrk;": "\u23b4",
+  "tcaron;": "\u0165",
+  "tcedil;": "\u0163",
+  "tcy;": "\u0442",
+  "tdot;": "\u20db",
+  "telrec;": "\u2315",
+  "tfr;": "\u{01d531}",
+  "there4;": "\u2234",
+  "therefore;": "\u2234",
+  "theta;": "\u03b8",
+  "thetasym;": "\u03d1",
+  "thetav;": "\u03d1",
+  "thickapprox;": "\u2248",
+  "thicksim;": "\u223c",
+  "thinsp;": "\u2009",
+  "thkap;": "\u2248",
+  "thksim;": "\u223c",
+  "thorn": "\xfe",
+  "thorn;": "\xfe",
+  "tilde;": "\u02dc",
+  "times": "\xd7",
+  "times;": "\xd7",
+  "timesb;": "\u22a0",
+  "timesbar;": "\u2a31",
+  "timesd;": "\u2a30",
+  "tint;": "\u222d",
+  "toea;": "\u2928",
+  "top;": "\u22a4",
+  "topbot;": "\u2336",
+  "topcir;": "\u2af1",
+  "topf;": "\u{01d565}",
+  "topfork;": "\u2ada",
+  "tosa;": "\u2929",
+  "tprime;": "\u2034",
+  "trade;": "\u2122",
+  "triangle;": "\u25b5",
+  "triangledown;": "\u25bf",
+  "triangleleft;": "\u25c3",
+  "trianglelefteq;": "\u22b4",
+  "triangleq;": "\u225c",
+  "triangleright;": "\u25b9",
+  "trianglerighteq;": "\u22b5",
+  "tridot;": "\u25ec",
+  "trie;": "\u225c",
+  "triminus;": "\u2a3a",
+  "triplus;": "\u2a39",
+  "trisb;": "\u29cd",
+  "tritime;": "\u2a3b",
+  "trpezium;": "\u23e2",
+  "tscr;": "\u{01d4c9}",
+  "tscy;": "\u0446",
+  "tshcy;": "\u045b",
+  "tstrok;": "\u0167",
+  "twixt;": "\u226c",
+  "twoheadleftarrow;": "\u219e",
+  "twoheadrightarrow;": "\u21a0",
+  "uArr;": "\u21d1",
+  "uHar;": "\u2963",
+  "uacute": "\xfa",
+  "uacute;": "\xfa",
+  "uarr;": "\u2191",
+  "ubrcy;": "\u045e",
+  "ubreve;": "\u016d",
+  "ucirc": "\xfb",
+  "ucirc;": "\xfb",
+  "ucy;": "\u0443",
+  "udarr;": "\u21c5",
+  "udblac;": "\u0171",
+  "udhar;": "\u296e",
+  "ufisht;": "\u297e",
+  "ufr;": "\u{01d532}",
+  "ugrave": "\xf9",
+  "ugrave;": "\xf9",
+  "uharl;": "\u21bf",
+  "uharr;": "\u21be",
+  "uhblk;": "\u2580",
+  "ulcorn;": "\u231c",
+  "ulcorner;": "\u231c",
+  "ulcrop;": "\u230f",
+  "ultri;": "\u25f8",
+  "umacr;": "\u016b",
+  "uml": "\xa8",
+  "uml;": "\xa8",
+  "uogon;": "\u0173",
+  "uopf;": "\u{01d566}",
+  "uparrow;": "\u2191",
+  "updownarrow;": "\u2195",
+  "upharpoonleft;": "\u21bf",
+  "upharpoonright;": "\u21be",
+  "uplus;": "\u228e",
+  "upsi;": "\u03c5",
+  "upsih;": "\u03d2",
+  "upsilon;": "\u03c5",
+  "upuparrows;": "\u21c8",
+  "urcorn;": "\u231d",
+  "urcorner;": "\u231d",
+  "urcrop;": "\u230e",
+  "uring;": "\u016f",
+  "urtri;": "\u25f9",
+  "uscr;": "\u{01d4ca}",
+  "utdot;": "\u22f0",
+  "utilde;": "\u0169",
+  "utri;": "\u25b5",
+  "utrif;": "\u25b4",
+  "uuarr;": "\u21c8",
+  "uuml": "\xfc",
+  "uuml;": "\xfc",
+  "uwangle;": "\u29a7",
+  "vArr;": "\u21d5",
+  "vBar;": "\u2ae8",
+  "vBarv;": "\u2ae9",
+  "vDash;": "\u22a8",
+  "vangrt;": "\u299c",
+  "varepsilon;": "\u03f5",
+  "varkappa;": "\u03f0",
+  "varnothing;": "\u2205",
+  "varphi;": "\u03d5",
+  "varpi;": "\u03d6",
+  "varpropto;": "\u221d",
+  "varr;": "\u2195",
+  "varrho;": "\u03f1",
+  "varsigma;": "\u03c2",
+  "varsubsetneq;": "\u228a\ufe00",
+  "varsubsetneqq;": "\u2acb\ufe00",
+  "varsupsetneq;": "\u228b\ufe00",
+  "varsupsetneqq;": "\u2acc\ufe00",
+  "vartheta;": "\u03d1",
+  "vartriangleleft;": "\u22b2",
+  "vartriangleright;": "\u22b3",
+  "vcy;": "\u0432",
+  "vdash;": "\u22a2",
+  "vee;": "\u2228",
+  "veebar;": "\u22bb",
+  "veeeq;": "\u225a",
+  "vellip;": "\u22ee",
+  "verbar;": "|",
+  "vert;": "|",
+  "vfr;": "\u{01d533}",
+  "vltri;": "\u22b2",
+  "vnsub;": "\u2282\u20d2",
+  "vnsup;": "\u2283\u20d2",
+  "vopf;": "\u{01d567}",
+  "vprop;": "\u221d",
+  "vrtri;": "\u22b3",
+  "vscr;": "\u{01d4cb}",
+  "vsubnE;": "\u2acb\ufe00",
+  "vsubne;": "\u228a\ufe00",
+  "vsupnE;": "\u2acc\ufe00",
+  "vsupne;": "\u228b\ufe00",
+  "vzigzag;": "\u299a",
+  "wcirc;": "\u0175",
+  "wedbar;": "\u2a5f",
+  "wedge;": "\u2227",
+  "wedgeq;": "\u2259",
+  "weierp;": "\u2118",
+  "wfr;": "\u{01d534}",
+  "wopf;": "\u{01d568}",
+  "wp;": "\u2118",
+  "wr;": "\u2240",
+  "wreath;": "\u2240",
+  "wscr;": "\u{01d4cc}",
+  "xcap;": "\u22c2",
+  "xcirc;": "\u25ef",
+  "xcup;": "\u22c3",
+  "xdtri;": "\u25bd",
+  "xfr;": "\u{01d535}",
+  "xhArr;": "\u27fa",
+  "xharr;": "\u27f7",
+  "xi;": "\u03be",
+  "xlArr;": "\u27f8",
+  "xlarr;": "\u27f5",
+  "xmap;": "\u27fc",
+  "xnis;": "\u22fb",
+  "xodot;": "\u2a00",
+  "xopf;": "\u{01d569}",
+  "xoplus;": "\u2a01",
+  "xotime;": "\u2a02",
+  "xrArr;": "\u27f9",
+  "xrarr;": "\u27f6",
+  "xscr;": "\u{01d4cd}",
+  "xsqcup;": "\u2a06",
+  "xuplus;": "\u2a04",
+  "xutri;": "\u25b3",
+  "xvee;": "\u22c1",
+  "xwedge;": "\u22c0",
+  "yacute": "\xfd",
+  "yacute;": "\xfd",
+  "yacy;": "\u044f",
+  "ycirc;": "\u0177",
+  "ycy;": "\u044b",
+  "yen": "\xa5",
+  "yen;": "\xa5",
+  "yfr;": "\u{01d536}",
+  "yicy;": "\u0457",
+  "yopf;": "\u{01d56a}",
+  "yscr;": "\u{01d4ce}",
+  "yucy;": "\u044e",
+  "yuml": "\xff",
+  "yuml;": "\xff",
+  "zacute;": "\u017a",
+  "zcaron;": "\u017e",
+  "zcy;": "\u0437",
+  "zdot;": "\u017c",
+  "zeetrf;": "\u2128",
+  "zeta;": "\u03b6",
+  "zfr;": "\u{01d537}",
+  "zhcy;": "\u0436",
+  "zigrarr;": "\u21dd",
+  "zopf;": "\u{01d56b}",
+  "zscr;": "\u{01d4cf}",
+  "zwj;": "\u200d",
+  "zwnj;": "\u200c",
+};
+
+Map<int, String> replacementCharacters = (() {
+  // TODO(jmesserly): fix this when Dart has literal maps with int keys.
+  var r = new Map<int, String>();
+  r[0x00] = "\uFFFD";
+  r[0x0d] = "\u000D";
+  r[0x80] = "\u20AC";
+  r[0x81] = "\u0081";
+  r[0x81] = "\u0081";
+  r[0x82] = "\u201A";
+  r[0x83] = "\u0192";
+  r[0x84] = "\u201E";
+  r[0x85] = "\u2026";
+  r[0x86] = "\u2020";
+  r[0x87] = "\u2021";
+  r[0x88] = "\u02C6";
+  r[0x89] = "\u2030";
+  r[0x8A] = "\u0160";
+  r[0x8B] = "\u2039";
+  r[0x8C] = "\u0152";
+  r[0x8D] = "\u008D";
+  r[0x8E] = "\u017D";
+  r[0x8F] = "\u008F";
+  r[0x90] = "\u0090";
+  r[0x91] = "\u2018";
+  r[0x92] = "\u2019";
+  r[0x93] = "\u201C";
+  r[0x94] = "\u201D";
+  r[0x95] = "\u2022";
+  r[0x96] = "\u2013";
+  r[0x97] = "\u2014";
+  r[0x98] = "\u02DC";
+  r[0x99] = "\u2122";
+  r[0x9A] = "\u0161";
+  r[0x9B] = "\u203A";
+  r[0x9C] = "\u0153";
+  r[0x9D] = "\u009D";
+  r[0x9E] = "\u017E";
+  r[0x9F] = "\u0178";
+  return r;
+})();
+
+final Map<String, String> encodings = const {
+  '437': 'cp437',
+  '850': 'cp850',
+  '852': 'cp852',
+  '855': 'cp855',
+  '857': 'cp857',
+  '860': 'cp860',
+  '861': 'cp861',
+  '862': 'cp862',
+  '863': 'cp863',
+  '865': 'cp865',
+  '866': 'cp866',
+  '869': 'cp869',
+  'ansix341968': 'ascii',
+  'ansix341986': 'ascii',
+  'arabic': 'iso8859-6',
+  'ascii': 'ascii',
+  'asmo708': 'iso8859-6',
+  'big5': 'big5',
+  'big5hkscs': 'big5hkscs',
+  'chinese': 'gbk',
+  'cp037': 'cp037',
+  'cp1026': 'cp1026',
+  'cp154': 'ptcp154',
+  'cp367': 'ascii',
+  'cp424': 'cp424',
+  'cp437': 'cp437',
+  'cp500': 'cp500',
+  'cp775': 'cp775',
+  'cp819': 'windows-1252',
+  'cp850': 'cp850',
+  'cp852': 'cp852',
+  'cp855': 'cp855',
+  'cp857': 'cp857',
+  'cp860': 'cp860',
+  'cp861': 'cp861',
+  'cp862': 'cp862',
+  'cp863': 'cp863',
+  'cp864': 'cp864',
+  'cp865': 'cp865',
+  'cp866': 'cp866',
+  'cp869': 'cp869',
+  'cp936': 'gbk',
+  'cpgr': 'cp869',
+  'cpis': 'cp861',
+  'csascii': 'ascii',
+  'csbig5': 'big5',
+  'cseuckr': 'cp949',
+  'cseucpkdfmtjapanese': 'euc_jp',
+  'csgb2312': 'gbk',
+  'cshproman8': 'hp-roman8',
+  'csibm037': 'cp037',
+  'csibm1026': 'cp1026',
+  'csibm424': 'cp424',
+  'csibm500': 'cp500',
+  'csibm855': 'cp855',
+  'csibm857': 'cp857',
+  'csibm860': 'cp860',
+  'csibm861': 'cp861',
+  'csibm863': 'cp863',
+  'csibm864': 'cp864',
+  'csibm865': 'cp865',
+  'csibm866': 'cp866',
+  'csibm869': 'cp869',
+  'csiso2022jp': 'iso2022_jp',
+  'csiso2022jp2': 'iso2022_jp_2',
+  'csiso2022kr': 'iso2022_kr',
+  'csiso58gb231280': 'gbk',
+  'csisolatin1': 'windows-1252',
+  'csisolatin2': 'iso8859-2',
+  'csisolatin3': 'iso8859-3',
+  'csisolatin4': 'iso8859-4',
+  'csisolatin5': 'windows-1254',
+  'csisolatin6': 'iso8859-10',
+  'csisolatinarabic': 'iso8859-6',
+  'csisolatincyrillic': 'iso8859-5',
+  'csisolatingreek': 'iso8859-7',
+  'csisolatinhebrew': 'iso8859-8',
+  'cskoi8r': 'koi8-r',
+  'csksc56011987': 'cp949',
+  'cspc775baltic': 'cp775',
+  'cspc850multilingual': 'cp850',
+  'cspc862latinhebrew': 'cp862',
+  'cspc8codepage437': 'cp437',
+  'cspcp852': 'cp852',
+  'csptcp154': 'ptcp154',
+  'csshiftjis': 'shift_jis',
+  'csunicode11utf7': 'utf-7',
+  'cyrillic': 'iso8859-5',
+  'cyrillicasian': 'ptcp154',
+  'ebcdiccpbe': 'cp500',
+  'ebcdiccpca': 'cp037',
+  'ebcdiccpch': 'cp500',
+  'ebcdiccphe': 'cp424',
+  'ebcdiccpnl': 'cp037',
+  'ebcdiccpus': 'cp037',
+  'ebcdiccpwt': 'cp037',
+  'ecma114': 'iso8859-6',
+  'ecma118': 'iso8859-7',
+  'elot928': 'iso8859-7',
+  'eucjp': 'euc_jp',
+  'euckr': 'cp949',
+  'extendedunixcodepackedformatforjapanese': 'euc_jp',
+  'gb18030': 'gb18030',
+  'gb2312': 'gbk',
+  'gb231280': 'gbk',
+  'gbk': 'gbk',
+  'greek': 'iso8859-7',
+  'greek8': 'iso8859-7',
+  'hebrew': 'iso8859-8',
+  'hproman8': 'hp-roman8',
+  'hzgb2312': 'hz',
+  'ibm037': 'cp037',
+  'ibm1026': 'cp1026',
+  'ibm367': 'ascii',
+  'ibm424': 'cp424',
+  'ibm437': 'cp437',
+  'ibm500': 'cp500',
+  'ibm775': 'cp775',
+  'ibm819': 'windows-1252',
+  'ibm850': 'cp850',
+  'ibm852': 'cp852',
+  'ibm855': 'cp855',
+  'ibm857': 'cp857',
+  'ibm860': 'cp860',
+  'ibm861': 'cp861',
+  'ibm862': 'cp862',
+  'ibm863': 'cp863',
+  'ibm864': 'cp864',
+  'ibm865': 'cp865',
+  'ibm866': 'cp866',
+  'ibm869': 'cp869',
+  'iso2022jp': 'iso2022_jp',
+  'iso2022jp2': 'iso2022_jp_2',
+  'iso2022kr': 'iso2022_kr',
+  'iso646irv1991': 'ascii',
+  'iso646us': 'ascii',
+  'iso88591': 'windows-1252',
+  'iso885910': 'iso8859-10',
+  'iso8859101992': 'iso8859-10',
+  'iso885911987': 'windows-1252',
+  'iso885913': 'iso8859-13',
+  'iso885914': 'iso8859-14',
+  'iso8859141998': 'iso8859-14',
+  'iso885915': 'iso8859-15',
+  'iso885916': 'iso8859-16',
+  'iso8859162001': 'iso8859-16',
+  'iso88592': 'iso8859-2',
+  'iso885921987': 'iso8859-2',
+  'iso88593': 'iso8859-3',
+  'iso885931988': 'iso8859-3',
+  'iso88594': 'iso8859-4',
+  'iso885941988': 'iso8859-4',
+  'iso88595': 'iso8859-5',
+  'iso885951988': 'iso8859-5',
+  'iso88596': 'iso8859-6',
+  'iso885961987': 'iso8859-6',
+  'iso88597': 'iso8859-7',
+  'iso885971987': 'iso8859-7',
+  'iso88598': 'iso8859-8',
+  'iso885981988': 'iso8859-8',
+  'iso88599': 'windows-1254',
+  'iso885991989': 'windows-1254',
+  'isoceltic': 'iso8859-14',
+  'isoir100': 'windows-1252',
+  'isoir101': 'iso8859-2',
+  'isoir109': 'iso8859-3',
+  'isoir110': 'iso8859-4',
+  'isoir126': 'iso8859-7',
+  'isoir127': 'iso8859-6',
+  'isoir138': 'iso8859-8',
+  'isoir144': 'iso8859-5',
+  'isoir148': 'windows-1254',
+  'isoir149': 'cp949',
+  'isoir157': 'iso8859-10',
+  'isoir199': 'iso8859-14',
+  'isoir226': 'iso8859-16',
+  'isoir58': 'gbk',
+  'isoir6': 'ascii',
+  'koi8r': 'koi8-r',
+  'koi8u': 'koi8-u',
+  'korean': 'cp949',
+  'ksc5601': 'cp949',
+  'ksc56011987': 'cp949',
+  'ksc56011989': 'cp949',
+  'l1': 'windows-1252',
+  'l10': 'iso8859-16',
+  'l2': 'iso8859-2',
+  'l3': 'iso8859-3',
+  'l4': 'iso8859-4',
+  'l5': 'windows-1254',
+  'l6': 'iso8859-10',
+  'l8': 'iso8859-14',
+  'latin1': 'windows-1252',
+  'latin10': 'iso8859-16',
+  'latin2': 'iso8859-2',
+  'latin3': 'iso8859-3',
+  'latin4': 'iso8859-4',
+  'latin5': 'windows-1254',
+  'latin6': 'iso8859-10',
+  'latin8': 'iso8859-14',
+  'latin9': 'iso8859-15',
+  'ms936': 'gbk',
+  'mskanji': 'shift_jis',
+  'pt154': 'ptcp154',
+  'ptcp154': 'ptcp154',
+  'r8': 'hp-roman8',
+  'roman8': 'hp-roman8',
+  'shiftjis': 'shift_jis',
+  'tis620': 'cp874',
+  'unicode11utf7': 'utf-7',
+  'us': 'ascii',
+  'usascii': 'ascii',
+  'utf16': 'utf-16',
+  'utf16be': 'utf-16-be',
+  'utf16le': 'utf-16-le',
+  'utf8': 'utf-8',
+  'windows1250': 'cp1250',
+  'windows1251': 'cp1251',
+  'windows1252': 'cp1252',
+  'windows1253': 'cp1253',
+  'windows1254': 'cp1254',
+  'windows1255': 'cp1255',
+  'windows1256': 'cp1256',
+  'windows1257': 'cp1257',
+  'windows1258': 'cp1258',
+  'windows936': 'gbk',
+  'x-x-big5': 'big5'
+};
diff --git a/pkg/third_party/html5lib/lib/src/encoding_parser.dart b/pkg/third_party/html5lib/lib/src/encoding_parser.dart
new file mode 100644
index 0000000..7b0edb8
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/encoding_parser.dart
@@ -0,0 +1,385 @@
+library encoding_parser;
+
+import 'dart:collection';
+import 'constants.dart';
+import 'inputstream.dart';
+import 'utils.dart';
+
+// TODO(jmesserly): I converted StopIteration to StateError("No more elements").
+// Seems strange to throw this from outside of an iterator though.
+/**
+ * String-like object with an associated position and various extra methods
+ * If the position is ever greater than the string length then an exception is
+ * raised.
+ */
+class EncodingBytes extends IterableBase<String> {
+  final String _bytes;
+  int _position = -1;
+
+  EncodingBytes(this._bytes);
+
+  Iterator<String> get iterator => _bytes.split('').iterator;
+
+  int get length => _bytes.length;
+
+  String next() {
+    var p = _position = _position + 1;
+    if (p >= length) {
+      throw new StateError("No more elements");
+    } else if (p < 0) {
+      throw new RangeError(p);
+    }
+    return _bytes[p];
+  }
+
+  String previous() {
+    var p = _position;
+    if (p >= length) {
+      throw new StateError("No more elements");
+    } else if (p < 0) {
+      throw new RangeError(p);
+    }
+    _position = p = p - 1;
+    return _bytes[p];
+  }
+
+  set position(int value) {
+    if (_position >= length) {
+      throw new StateError("No more elements");
+    }
+    _position = value;
+  }
+
+  int get position {
+    if (_position >= length) {
+      throw new StateError("No more elements");
+    }
+    if (_position >= 0) {
+      return _position;
+    } else {
+      return 0;
+    }
+  }
+
+  String get currentByte => _bytes[position];
+
+  /** Skip past a list of characters. Defaults to skipping [isWhitespace]. */
+  String skipChars([CharPreciate skipChars]) {
+    if (skipChars == null) skipChars = isWhitespace;
+    var p = position;  // use property for the error-checking
+    while (p < length) {
+      var c = _bytes[p];
+      if (!skipChars(c)) {
+        _position = p;
+        return c;
+      }
+      p += 1;
+    }
+    _position = p;
+    return null;
+  }
+
+  String skipUntil(CharPreciate untilChars) {
+    var p = position;
+    while (p < length) {
+      var c = _bytes[p];
+      if (untilChars(c)) {
+        _position = p;
+        return c;
+      }
+      p += 1;
+    }
+    return null;
+  }
+
+  /**
+   * Look for a sequence of bytes at the start of a string. If the bytes
+   * are found return true and advance the position to the byte after the
+   * match. Otherwise return false and leave the position alone.
+   */
+  bool matchBytes(String bytes) {
+    var p = position;
+    if (_bytes.length < p + bytes.length) {
+      return false;
+    }
+    var data = _bytes.substring(p, p + bytes.length);
+    if (data == bytes) {
+      position += bytes.length;
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Look for the next sequence of bytes matching a given sequence. If
+   * a match is found advance the position to the last byte of the match
+   */
+  bool jumpTo(String bytes) {
+    var newPosition = _bytes.indexOf(bytes, position);
+    if (newPosition >= 0) {
+      _position = newPosition + bytes.length - 1;
+      return true;
+    } else {
+      throw new StateError("No more elements");
+    }
+  }
+
+  String slice(int start, [int end]) {
+    if (end == null) end = length;
+    if (end < 0) end += length;
+    return _bytes.substring(start, end - start);
+  }
+}
+
+/** Mini parser for detecting character encoding from meta elements. */
+class EncodingParser {
+  final EncodingBytes data;
+  String encoding;
+
+  /** [bytes] - the data to work on for encoding detection. */
+  EncodingParser(List<int> bytes)
+      // Note: this is intentionally interpreting bytes as codepoints.
+      : data = new EncodingBytes(new String.fromCharCodes(bytes).toLowerCase());
+
+  String getEncoding() {
+    final methodDispatch = [
+      ["<!--", handleComment],
+      ["<meta", handleMeta],
+      ["</", handlePossibleEndTag],
+      ["<!", handleOther],
+      ["<?", handleOther],
+      ["<", handlePossibleStartTag]];
+
+    try {
+      for (var byte in data) {
+        var keepParsing = true;
+        for (var dispatch in methodDispatch) {
+          if (data.matchBytes(dispatch[0])) {
+            try {
+              keepParsing = dispatch[1]();
+              break;
+            } on StateError catch (e) {
+              keepParsing = false;
+              break;
+            }
+          }
+        }
+        if (!keepParsing) {
+          break;
+        }
+      }
+    } on StateError catch (e) {
+      // Catch this here to match behavior of Python's StopIteration
+    }
+    return encoding;
+  }
+
+  /** Skip over comments. */
+  bool handleComment() => data.jumpTo("-->");
+
+  bool handleMeta() {
+    if (!isWhitespace(data.currentByte)) {
+      // if we have <meta not followed by a space so just keep going
+      return true;
+    }
+    // We have a valid meta element we want to search for attributes
+    while (true) {
+      // Try to find the next attribute after the current position
+      var attr = getAttribute();
+      if (attr == null) return true;
+
+      if (attr[0] == "charset") {
+        var tentativeEncoding = attr[1];
+        var codec = codecName(tentativeEncoding);
+        if (codec != null) {
+          encoding = codec;
+          return false;
+        }
+      } else if (attr[0] == "content") {
+        var contentParser = new ContentAttrParser(new EncodingBytes(attr[1]));
+        var tentativeEncoding = contentParser.parse();
+        var codec = codecName(tentativeEncoding);
+        if (codec != null) {
+          encoding = codec;
+          return false;
+        }
+      }
+    }
+  }
+
+  bool handlePossibleStartTag() => handlePossibleTag(false);
+
+  bool handlePossibleEndTag() {
+    data.next();
+    return handlePossibleTag(true);
+  }
+
+  bool handlePossibleTag(bool endTag) {
+    if (!isLetter(data.currentByte)) {
+      //If the next byte is not an ascii letter either ignore this
+      //fragment (possible start tag case) or treat it according to
+      //handleOther
+      if (endTag) {
+        data.previous();
+        handleOther();
+      }
+      return true;
+    }
+
+    var c = data.skipUntil(isSpaceOrAngleBracket);
+    if (c == "<") {
+      // return to the first step in the overall "two step" algorithm
+      // reprocessing the < byte
+      data.previous();
+    } else {
+      //Read all attributes
+      var attr = getAttribute();
+      while (attr != null) {
+        attr = getAttribute();
+      }
+    }
+    return true;
+  }
+
+  bool handleOther() => data.jumpTo(">");
+
+  /**
+   * Return a name,value pair for the next attribute in the stream,
+   * if one is found, or null
+   */
+  List<String> getAttribute() {
+    // Step 1 (skip chars)
+    var c = data.skipChars((x) => x == "/" || isWhitespace(x));
+    // Step 2
+    if (c == ">" || c == null) {
+      return null;
+    }
+    // Step 3
+    var attrName = [];
+    var attrValue = [];
+    // Step 4 attribute name
+    while (true) {
+      if (c == null) {
+        return null;
+      } else if (c == "=" && attrName.length > 0) {
+        break;
+      } else if (isWhitespace(c)) {
+        // Step 6!
+        c = data.skipChars();
+        c = data.next();
+        break;
+      } else if (c == "/" || c == ">") {
+        return [attrName.join(), ""];
+      } else if (isLetter(c)) {
+        attrName.add(c.toLowerCase());
+      } else {
+        attrName.add(c);
+      }
+      // Step 5
+      c = data.next();
+    }
+    // Step 7
+    if (c != "=") {
+      data.previous();
+      return [attrName.join(), ""];
+    }
+    // Step 8
+    data.next();
+    // Step 9
+    c = data.skipChars();
+    // Step 10
+    if (c == "'" || c == '"') {
+      // 10.1
+      var quoteChar = c;
+      while (true) {
+        // 10.2
+        c = data.next();
+        if (c == quoteChar) {
+          // 10.3
+          data.next();
+          return [attrName.join(), attrValue.join()];
+        } else if (isLetter(c)) {
+          // 10.4
+          attrValue.add(c.toLowerCase());
+        } else {
+          // 10.5
+          attrValue.add(c);
+        }
+      }
+    } else if (c == ">") {
+      return [attrName.join(), ""];
+    } else if (c == null) {
+      return null;
+    } else if (isLetter(c)) {
+      attrValue.add(c.toLowerCase());
+    } else {
+      attrValue.add(c);
+    }
+    // Step 11
+    while (true) {
+      c = data.next();
+      if (isSpaceOrAngleBracket(c)) {
+        return [attrName.join(), attrValue.join()];
+      } else if (c == null) {
+        return null;
+      } else if (isLetter(c)) {
+        attrValue.add(c.toLowerCase());
+      } else {
+        attrValue.add(c);
+      }
+    }
+  }
+}
+
+
+class ContentAttrParser {
+  final EncodingBytes data;
+
+  ContentAttrParser(this.data);
+
+  String parse() {
+    try {
+      // Check if the attr name is charset
+      // otherwise return
+      data.jumpTo("charset");
+      data.position += 1;
+      data.skipChars();
+      if (data.currentByte != "=") {
+        // If there is no = sign keep looking for attrs
+        return null;
+      }
+      data.position += 1;
+      data.skipChars();
+      // Look for an encoding between matching quote marks
+      if (data.currentByte == '"' || data.currentByte == "'") {
+        var quoteMark = data.currentByte;
+        data.position += 1;
+        var oldPosition = data.position;
+        if (data.jumpTo(quoteMark)) {
+          return data.slice(oldPosition, data.position);
+        } else {
+          return null;
+        }
+      } else {
+        // Unquoted value
+        var oldPosition = data.position;
+        try {
+          data.skipUntil(isWhitespace);
+          return data.slice(oldPosition, data.position);
+        } on StateError catch (e) {
+          //Return the whole remaining value
+          return data.slice(oldPosition);
+        }
+      }
+    } on StateError catch (e) {
+      return null;
+    }
+  }
+}
+
+
+bool isSpaceOrAngleBracket(String char) {
+  return char == ">" || char == "<" || isWhitespace(char);
+}
+
+typedef bool CharPreciate(String char);
diff --git a/pkg/third_party/html5lib/lib/src/inputstream.dart b/pkg/third_party/html5lib/lib/src/inputstream.dart
new file mode 100644
index 0000000..29ee1dc
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/inputstream.dart
@@ -0,0 +1,310 @@
+library inputstream;
+
+import 'dart:collection';
+import 'dart:utf';
+import 'package:source_maps/span.dart' show SourceFile;
+import 'char_encodings.dart';
+import 'constants.dart';
+import 'utils.dart';
+import 'encoding_parser.dart';
+
+/** Hooks to call into dart:io without directly referencing it. */
+class ConsoleSupport {
+  List<int> bytesFromFile(source) => null;
+}
+
+// TODO(jmesserly): use lazy init here when supported.
+ConsoleSupport consoleSupport = new ConsoleSupport();
+
+/**
+ * Provides a unicode stream of characters to the HtmlTokenizer.
+ *
+ * This class takes care of character encoding and removing or replacing
+ * incorrect byte-sequences and also provides column and line tracking.
+ */
+class HtmlInputStream {
+  /**
+   * Number of bytes to use when looking for a meta element with
+   * encoding information.
+   */
+  static const int numBytesMeta = 512;
+
+  /** Encoding to use if no other information can be found. */
+  static const String defaultEncoding = 'windows-1252';
+
+  /** The name of the character encoding. */
+  String charEncodingName;
+
+  /** True if we are certain about [charEncodingName], false for tenative. */
+  bool charEncodingCertain = true;
+
+  final bool generateSpans;
+
+  /** Location where the contents of the stream were found. */
+  final String sourceUrl;
+
+  List<int> _rawBytes;
+
+  /** Raw UTF-16 codes, used if a Dart String is passed in. */
+  Iterable<int> _rawChars;
+
+  Queue<String> errors;
+
+  SourceFile fileInfo;
+
+  List<int> _lineStarts;
+
+  List<int> _chars;
+
+  int _offset;
+
+  /**
+   * Initialises the HtmlInputStream.
+   *
+   * HtmlInputStream(source, [encoding]) -> Normalized stream from source
+   * for use by html5lib.
+   *
+   * [source] can be either a [String] or a [List<int>] containing the raw
+   * bytes, or a file if [consoleSupport] is initialized.
+   *
+   * The optional encoding parameter must be a string that indicates
+   * the encoding.  If specified, that encoding will be used,
+   * regardless of any BOM or later declaration (such as in a meta
+   * element)
+   *
+   * [parseMeta] - Look for a <meta> element containing encoding information
+   */
+  HtmlInputStream(source, [String encoding, bool parseMeta = true,
+        this.generateSpans = false, this.sourceUrl])
+      : charEncodingName = codecName(encoding) {
+
+    if (source is String) {
+      _rawChars = toCodepoints(source);
+      charEncodingName = 'utf-8';
+      charEncodingCertain = true;
+    } else if (source is List<int>) {
+      _rawBytes = source;
+    } else {
+      // TODO(jmesserly): it's unfortunate we need to read all bytes in advance,
+      // but it's necessary because of how the UTF decoders work.
+      _rawBytes = consoleSupport.bytesFromFile(source);
+
+      if (_rawBytes == null) {
+        // TODO(jmesserly): we should accept some kind of stream API too.
+        // Unfortunately dart:io InputStream is async only, which won't work.
+        throw new ArgumentError("'source' must be a String or "
+            "List<int> (of bytes). You can also pass a RandomAccessFile if you"
+            "`import 'package:html5lib/parser_console.dart'` and call "
+            "`useConsole()`.");
+      }
+    }
+
+    // Detect encoding iff no explicit "transport level" encoding is supplied
+    if (charEncodingName == null) {
+      detectEncoding(parseMeta);
+    }
+
+    reset();
+  }
+
+  void reset() {
+    errors = new Queue<String>();
+
+    _offset = 0;
+    _lineStarts = <int>[0];
+    _chars = <int>[];
+
+    if (_rawChars == null) {
+      _rawChars = decodeBytes(charEncodingName, _rawBytes);
+    }
+
+    bool skipNewline = false;
+    for (var c in _rawChars) {
+      if (skipNewline) {
+        skipNewline = false;
+        if (c == NEWLINE) continue;
+      }
+
+      if (invalidUnicode(c)) errors.add('invalid-codepoint');
+
+      if (0xD800 <= c && c <= 0xDFFF) {
+        c = 0xFFFD;
+      } else if (c == RETURN) {
+        skipNewline = true;
+        c = NEWLINE;
+      }
+
+      _chars.add(c);
+      if (c == NEWLINE) _lineStarts.add(_chars.length);
+    }
+
+    // Free decoded characters if they aren't needed anymore.
+    if (_rawBytes != null) _rawChars = null;
+
+    fileInfo = new SourceFile(sourceUrl, _lineStarts,
+        generateSpans ? _chars : null);
+  }
+
+
+  void detectEncoding([bool parseMeta = true]) {
+    // First look for a BOM
+    // This will also read past the BOM if present
+    charEncodingName = detectBOM();
+    charEncodingCertain = true;
+
+    // If there is no BOM need to look for meta elements with encoding
+    // information
+    if (charEncodingName == null && parseMeta) {
+      charEncodingName = detectEncodingMeta();
+      charEncodingCertain = false;
+    }
+    // If all else fails use the default encoding
+    if (charEncodingName == null) {
+      charEncodingCertain = false;
+      charEncodingName = defaultEncoding;
+    }
+
+    // Substitute for equivalent encodings:
+    if (charEncodingName.toLowerCase() == 'iso-8859-1') {
+      charEncodingName = 'windows-1252';
+    }
+  }
+
+  void changeEncoding(String newEncoding) {
+    if (_rawBytes == null) {
+      // We should never get here -- if encoding is certain we won't try to
+      // change it.
+      throw new StateError('cannot change encoding when parsing a String.');
+    }
+
+    newEncoding = codecName(newEncoding);
+    if (const ['utf-16', 'utf-16-be', 'utf-16-le'].contains(newEncoding)) {
+      newEncoding = 'utf-8';
+    }
+    if (newEncoding == null) {
+      return;
+    } else if (newEncoding == charEncodingName) {
+      charEncodingCertain = true;
+    } else {
+      charEncodingName = newEncoding;
+      charEncodingCertain = true;
+      _rawChars = null;
+      reset();
+      throw new ReparseException(
+          'Encoding changed from $charEncodingName to $newEncoding');
+    }
+  }
+
+  /**
+   * Attempts to detect at BOM at the start of the stream. If
+   * an encoding can be determined from the BOM return the name of the
+   * encoding otherwise return null.
+   */
+  String detectBOM() {
+    // Try detecting the BOM using bytes from the string
+    if (hasUtf8Bom(_rawBytes)) {
+      return 'utf-8';
+    }
+    // Note: we don't need to remember whether it was big or little endian
+    // because the decoder will do that later. It will also eat the BOM for us.
+    if (hasUtf16Bom(_rawBytes)) {
+      return 'utf-16';
+    }
+    if (hasUtf32Bom(_rawBytes)) {
+      return 'utf-32';
+    }
+    return null;
+  }
+
+  /** Report the encoding declared by the meta element. */
+  String detectEncodingMeta() {
+    var parser = new EncodingParser(slice(_rawBytes, 0, numBytesMeta));
+    var encoding = parser.getEncoding();
+
+    if (const ['utf-16', 'utf-16-be', 'utf-16-le'].contains(encoding)) {
+      encoding = 'utf-8';
+    }
+
+    return encoding;
+  }
+
+  /**
+   * Returns the current offset in the stream, i.e. the number of codepoints
+   * since the start of the file.
+   */
+  int get position => _offset;
+
+  /**
+   * Read one character from the stream or queue if available. Return
+   * EOF when EOF is reached.
+   */
+  String char() {
+    if (_offset >= _chars.length) return EOF;
+    return new String.fromCharCodes([_chars[_offset++]]);
+  }
+
+  String peekChar() {
+    if (_offset >= _chars.length) return EOF;
+    return new String.fromCharCodes([_chars[_offset]]);
+  }
+
+  /**
+   * Returns a string of characters from the stream up to but not
+   * including any character in 'characters' or EOF.
+   */
+  String charsUntil(String characters, [bool opposite = false]) {
+    int start = _offset;
+    String c;
+    while ((c = peekChar()) != null && characters.contains(c) == opposite) {
+      _offset++;
+    }
+
+    return new String.fromCharCodes(_chars.sublist(start, _offset));
+  }
+
+  void unget(String ch) {
+    // Only one character is allowed to be ungotten at once - it must
+    // be consumed again before any further call to unget
+    if (ch != null) {
+      _offset--;
+      assert(peekChar() == ch);
+    }
+  }
+}
+
+
+// TODO(jmesserly): the Python code used a regex to check for this. But
+// Dart doesn't let you create a regexp with invalid characters.
+bool invalidUnicode(int c) {
+  if (0x0001 <= c && c <= 0x0008) return true;
+  if (0x000E <= c && c <= 0x001F) return true;
+  if (0x007F <= c && c <= 0x009F) return true;
+  if (0xD800 <= c && c <= 0xDFFF) return true;
+  if (0xFDD0 <= c && c <= 0xFDEF) return true;
+  switch (c) {
+    case 0x000B: case 0xFFFE: case 0xFFFF: case 0x01FFFE: case 0x01FFFF:
+    case 0x02FFFE: case 0x02FFFF: case 0x03FFFE: case 0x03FFFF:
+    case 0x04FFFE: case 0x04FFFF: case 0x05FFFE: case 0x05FFFF:
+    case 0x06FFFE: case 0x06FFFF: case 0x07FFFE: case 0x07FFFF:
+    case 0x08FFFE: case 0x08FFFF: case 0x09FFFE: case 0x09FFFF:
+    case 0x0AFFFE: case 0x0AFFFF: case 0x0BFFFE: case 0x0BFFFF:
+    case 0x0CFFFE: case 0x0CFFFF: case 0x0DFFFE: case 0x0DFFFF:
+    case 0x0EFFFE: case 0x0EFFFF: case 0x0FFFFE: case 0x0FFFFF:
+    case 0x10FFFE: case 0x10FFFF:
+      return true;
+  }
+  return false;
+}
+
+/**
+ * Return the python codec name corresponding to an encoding or null if the
+ * string doesn't correspond to a valid encoding.
+ */
+String codecName(String encoding) {
+  final asciiPunctuation = new RegExp(
+      "[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]");
+
+  if (encoding == null) return null;
+  var canonicalName = encoding.replaceAll(asciiPunctuation, '').toLowerCase();
+  return encodings[canonicalName];
+}
diff --git a/pkg/third_party/html5lib/lib/src/list_proxy.dart b/pkg/third_party/html5lib/lib/src/list_proxy.dart
new file mode 100644
index 0000000..99adb3f
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/list_proxy.dart
@@ -0,0 +1,88 @@
+// TODO(jmesserly): remove this once we have a subclassable growable list
+// in our libraries.
+
+/** A [List] proxy that you can subclass. */
+library list_proxy;
+
+import 'dart:collection';
+
+// TOOD(jmesserly): this needs to be removed, but fixing NodeList is tricky.
+class ListProxy<E> extends IterableBase<E> implements List<E> {
+
+  /** The inner [List<T>] with the actual storage. */
+  final List<E> _list;
+
+  /**
+   * Creates a list proxy.
+   * You can optionally specify the list to use for [storage] of the items,
+   * otherwise this will create a [List<E>].
+   */
+  ListProxy([List<E> storage])
+     : _list = storage != null ? storage : <E>[];
+
+  // TODO(jmesserly): This should be on List.
+  // See http://code.google.com/p/dart/issues/detail?id=947
+  bool remove(E item) {
+    int i = indexOf(item);
+    if (i == -1) return false;
+    removeAt(i);
+    return true;
+  }
+
+  void insert(int index, E item) => _list.insert(index, item);
+
+  // Override from Iterable to fix performance
+  // Length and last become O(1) instead of O(N)
+  // The others are just different constant factor.
+  int get length => _list.length;
+  E get last => _list.last;
+  E get first => _list.first;
+  E get single => _list.single;
+
+  // From Iterable
+  Iterator<E> get iterator => _list.iterator;
+
+  // From List
+  E operator [](int index) => _list[index];
+  operator []=(int index, E value) { _list[index] = value; }
+  set length(int value) { _list.length = value; }
+  void add(E value) { _list.add(value); }
+
+  void addLast(E value) { add(value); }
+  void addAll(Iterable<E> collection) { _list.addAll(collection); }
+  void sort([int compare(E a, E b)]) { _list.sort(compare); }
+
+  int indexOf(E element, [int start = 0]) => _list.indexOf(element, start);
+  int lastIndexOf(E element, [int start]) => _list.lastIndexOf(element, start);
+  void clear() { _list.clear(); }
+
+  E removeAt(int index) => _list.removeAt(index);
+  E removeLast() => _list.removeLast();
+
+  void removeWhere(bool test(E element)) => _list.removeWhere(test);
+  void retainWhere(bool test(E element)) => _list.retainWhere(test);
+
+  List<E> sublist(int start, [int end]) => _list.sublist(start, end);
+
+  List<E> getRange(int start, int end) => _list.getRange(start, end);
+
+  void setRange(int start, int length, List<E> from, [int startFrom = 0]) {
+    _list.setRange(start, length, from, startFrom);
+  }
+  void removeRange(int start, int length) { _list.removeRange(start, length); }
+  void insertAll(int index, Iterable<E> iterable) {
+    _list.insertAll(index, iterable);
+  }
+
+  Iterable<E> get reversed => _list.reversed;
+
+  Map<int, E> asMap() => _list.asMap();
+
+  void replaceRange(int start, int end, Iterable<E> newContents) =>
+      _list.replaceRange(start, end, newContents);
+
+  void setAll(int index, Iterable<E> iterable) => _list.setAll(index, iterable);
+
+  void fillRange(int start, int end, [E fillValue])
+      => _list.fillRange(start, end, fillValue);
+}
diff --git a/pkg/third_party/html5lib/lib/src/token.dart b/pkg/third_party/html5lib/lib/src/token.dart
new file mode 100644
index 0000000..1e790da
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/token.dart
@@ -0,0 +1,122 @@
+/** This library contains token types used by the html5 tokenizer. */
+library token;
+
+import 'dart:collection';
+import 'package:source_maps/span.dart' show FileSpan;
+
+/** An html5 token. */
+abstract class Token {
+  FileSpan span;
+
+  int get kind;
+}
+
+abstract class TagToken extends Token {
+  String name;
+
+  bool selfClosing;
+
+  TagToken(this.name, this.selfClosing);
+}
+
+class StartTagToken extends TagToken {
+  /**
+   * The tag's attributes. A map from the name to the value, where the name
+   * can be a [String] or [AttributeName].
+   */
+  LinkedHashMap<dynamic, String> data;
+
+  /** The attribute spans if requested. Otherwise null. */
+  List<TagAttribute> attributeSpans;
+
+  bool selfClosingAcknowledged;
+
+  /** The namespace. This is filled in later during tree building. */
+  String namespace;
+
+  StartTagToken(String name, {this.data, bool selfClosing: false,
+      this.selfClosingAcknowledged: false, this.namespace})
+      : super(name, selfClosing);
+
+  int get kind => TokenKind.startTag;
+}
+
+class EndTagToken extends TagToken {
+  EndTagToken(String name, {bool selfClosing: false})
+      : super(name, selfClosing);
+
+  int get kind => TokenKind.endTag;
+}
+
+abstract class StringToken extends Token {
+  String data;
+  StringToken(this.data);
+}
+
+class ParseErrorToken extends StringToken {
+  /** Extra information that goes along with the error message. */
+  Map messageParams;
+
+  ParseErrorToken(String data, {this.messageParams}) : super(data);
+
+  int get kind => TokenKind.parseError;
+}
+
+class CharactersToken extends StringToken {
+  CharactersToken([String data]) : super(data);
+
+  int get kind => TokenKind.characters;
+}
+
+class SpaceCharactersToken extends StringToken {
+  SpaceCharactersToken([String data]) : super(data);
+
+  int get kind => TokenKind.spaceCharacters;
+}
+
+class CommentToken extends StringToken {
+  CommentToken([String data]) : super(data);
+
+  int get kind => TokenKind.comment;
+}
+
+class DoctypeToken extends Token {
+  String publicId;
+  String systemId;
+  String name = "";
+  bool correct;
+
+  DoctypeToken({this.publicId, this.systemId, this.correct: false});
+
+  int get kind => TokenKind.doctype;
+}
+
+/**
+ * These are used by the tokenizer to build up the attribute map.
+ * They're also used by [StartTagToken.attributeSpans] if attribute spans are
+ * requested.
+ */
+class TagAttribute {
+  String name;
+  String value;
+
+  // The spans of the attribute. This is not used unless we are computing an
+  // attribute span on demand.
+  int start;
+  int end;
+  int startValue;
+  int endValue;
+
+  TagAttribute(this.name, [this.value = '']);
+}
+
+
+class TokenKind {
+  static const int spaceCharacters = 0;
+  static const int characters = 1;
+  static const int startTag = 2;
+  static const int endTag = 3;
+  static const int comment = 4;
+  static const int doctype = 5;
+  static const int parseError = 6;
+}
diff --git a/pkg/third_party/html5lib/lib/src/tokenizer.dart b/pkg/third_party/html5lib/lib/src/tokenizer.dart
new file mode 100644
index 0000000..2c2ada7
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/tokenizer.dart
@@ -0,0 +1,1902 @@
+library tokenizer;
+
+import 'dart:collection';
+import 'dart:math';
+import 'package:html5lib/parser.dart' show HtmlParser;
+import 'package:source_maps/span.dart' show Span, FileSpan;
+import 'constants.dart';
+import 'inputstream.dart';
+import 'token.dart';
+import 'utils.dart';
+
+// Group entities by their first character, for faster lookups
+
+// TODO(jmesserly): we could use a better data structure here like a trie, if
+// we had it implemented in Dart.
+Map<String, List<String>> entitiesByFirstChar = (() {
+  var result = {};
+  for (var k in entities.keys) {
+    result.putIfAbsent(k[0], () => []).add(k);
+  }
+  return result;
+})();
+
+// TODO(jmesserly): lots of ways to make this faster:
+// - use char codes everywhere instead of 1-char strings
+// - use switch instead of contains, indexOf
+// - use switch instead of the sequential if tests
+// - avoid string concat
+
+/**
+ * This class takes care of tokenizing HTML.
+ */
+class HtmlTokenizer implements Iterator<Token> {
+  // TODO(jmesserly): a lot of these could be made private
+
+  final HtmlInputStream stream;
+
+  final bool lowercaseElementName;
+
+  final bool lowercaseAttrName;
+
+  /** True to generate spans in for [Token.span]. */
+  final bool generateSpans;
+
+  /** True to generate spans for attributes. */
+  final bool attributeSpans;
+
+  /**
+   * This reference to the parser is used for correct CDATA handling.
+   * The [HtmlParser] will set this at construction time.
+   */
+  HtmlParser parser;
+
+  final Queue<Token> tokenQueue;
+
+  /** Holds the token that is currently being processed. */
+  Token currentToken;
+
+  /**
+   * Holds a reference to the method to be invoked for the next parser state.
+   */
+  // TODO(jmesserly): the type should be "Predicate" but a dart2js checked mode
+  // bug prevents us from doing that. See http://dartbug.com/12465
+  Function state;
+
+  String temporaryBuffer;
+
+  int _lastOffset;
+
+  // TODO(jmesserly): ideally this would be a LinkedHashMap and we wouldn't add
+  // an item until it's ready. But the code doesn't have a clear notion of when
+  // it's "done" with the attribute.
+  List<TagAttribute> _attributes;
+  Set<String> _attributeNames;
+
+  HtmlTokenizer(doc, {String encoding, bool parseMeta: true,
+      this.lowercaseElementName: true, this.lowercaseAttrName: true,
+      bool generateSpans: false, String sourceUrl, this.attributeSpans: false})
+      : stream = new HtmlInputStream(
+            doc, encoding, parseMeta, generateSpans, sourceUrl),
+        tokenQueue = new Queue(),
+        generateSpans = generateSpans {
+    reset();
+  }
+
+  TagToken get currentTagToken => currentToken;
+  DoctypeToken get currentDoctypeToken => currentToken;
+  StringToken get currentStringToken => currentToken;
+
+  Token _current;
+  Token get current => _current;
+
+  String get _attributeName => _attributes.last.name;
+  set _attributeName(String value) {
+    _attributes.last.name = value;
+  }
+
+  String get _attributeValue => _attributes.last.value;
+  set _attributeValue(String value) {
+    _attributes.last.value = value;
+  }
+
+  void _markAttributeEnd(int offset) {
+    if (attributeSpans) _attributes.last.end = stream.position + offset;
+  }
+
+  void _markAttributeValueStart(int offset) {
+    if (attributeSpans) _attributes.last.startValue = stream.position + offset;
+  }
+
+  void _markAttributeValueEnd(int offset) {
+    if (attributeSpans) {
+      _attributes.last.endValue = stream.position + offset;
+      _markAttributeEnd(offset);
+    }
+  }
+
+  // Note: we could track the name span here, if we need it.
+  void _markAttributeNameEnd(int offset) => _markAttributeEnd(offset);
+
+  void _addAttribute(String name) {
+    if (_attributes == null) _attributes = [];
+    var attr = new TagAttribute(name);
+    _attributes.add(attr);
+    if (attributeSpans) attr.start = stream.position - name.length;
+  }
+
+  /**
+   * This is where the magic happens.
+   *
+   * We do our usually processing through the states and when we have a token
+   * to return we yield the token which pauses processing until the next token
+   * is requested.
+   */
+  bool moveNext() {
+    // Start processing. When EOF is reached state will return false;
+    // instead of true and the loop will terminate.
+    while (stream.errors.length == 0 && tokenQueue.length == 0) {
+      if (!state()) {
+        _current = null;
+        return false;
+      }
+    }
+    if (stream.errors.length > 0) {
+      _current = new ParseErrorToken(stream.errors.removeFirst());
+    } else {
+      assert (tokenQueue.length > 0);
+      _current = tokenQueue.removeFirst();
+    }
+    return true;
+  }
+
+  /**
+   * Resets the tokenizer state. Calling this does not reset the [stream] or
+   * the [parser].
+   */
+  void reset() {
+    _lastOffset = 0;
+    tokenQueue.clear();
+    currentToken = null;
+    temporaryBuffer = null;
+    _attributes = null;
+    _attributeNames = null;
+    state = dataState;
+  }
+
+  /** Adds a token to the queue. Sets the span if needed. */
+  void _addToken(Token token) {
+    if (generateSpans && token.span == null) {
+      int offset = stream.position;
+      token.span = new FileSpan(stream.fileInfo, _lastOffset, offset);
+      if (token is! ParseErrorToken) {
+        _lastOffset = offset;
+      }
+    }
+    tokenQueue.add(token);
+  }
+
+  /**
+   * This function returns either U+FFFD or the character based on the
+   * decimal or hexadecimal representation. It also discards ";" if present.
+   * If not present it will add a [ParseErrorToken].
+   */
+  String consumeNumberEntity(bool isHex) {
+    var allowed = isDigit;
+    var radix = 10;
+    if (isHex) {
+      allowed = isHexDigit;
+      radix = 16;
+    }
+
+    var charStack = [];
+
+    // Consume all the characters that are in range while making sure we
+    // don't hit an EOF.
+    var c = stream.char();
+    while (allowed(c) && c != EOF) {
+      charStack.add(c);
+      c = stream.char();
+    }
+
+    // Convert the set of characters consumed to an int.
+    var charAsInt = parseIntRadix(charStack.join(), radix);
+
+    // Certain characters get replaced with others
+    var char = replacementCharacters[charAsInt];
+    if (char != null) {
+      _addToken(new ParseErrorToken(
+          "illegal-codepoint-for-numeric-entity",
+          messageParams: {"charAsInt": charAsInt}));
+    } else if ((0xD800 <= charAsInt && charAsInt <= 0xDFFF)
+        || (charAsInt > 0x10FFFF)) {
+      char = "\uFFFD";
+      _addToken(new ParseErrorToken(
+          "illegal-codepoint-for-numeric-entity",
+          messageParams: {"charAsInt": charAsInt}));
+    } else {
+      // Should speed up this check somehow (e.g. move the set to a constant)
+      if ((0x0001 <= charAsInt && charAsInt <= 0x0008) ||
+          (0x000E <= charAsInt && charAsInt <= 0x001F) ||
+          (0x007F <= charAsInt && charAsInt <= 0x009F) ||
+          (0xFDD0 <= charAsInt && charAsInt <= 0xFDEF) ||
+          const [0x000B, 0xFFFE, 0xFFFF, 0x1FFFE,
+                0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE,
+                0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE,
+                0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE,
+                0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE,
+                0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE,
+                0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
+                0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE,
+                0xFFFFF, 0x10FFFE, 0x10FFFF].contains(charAsInt)) {
+        _addToken(new ParseErrorToken(
+            "illegal-codepoint-for-numeric-entity",
+            messageParams: {"charAsInt": charAsInt}));
+      }
+      char = new String.fromCharCodes([charAsInt]);
+    }
+
+    // Discard the ; if present. Otherwise, put it back on the queue and
+    // invoke parseError on parser.
+    if (c != ";") {
+      _addToken(new ParseErrorToken(
+          "numeric-entity-without-semicolon"));
+      stream.unget(c);
+    }
+    return char;
+  }
+
+  void consumeEntity({String allowedChar, bool fromAttribute: false}) {
+    // Initialise to the default output for when no entity is matched
+    var output = "&";
+
+    var charStack = [stream.char()];
+    if (isWhitespace(charStack[0]) || charStack[0] == '<' || charStack[0] == '&'
+        || charStack[0] == EOF || allowedChar == charStack[0]) {
+      stream.unget(charStack[0]);
+    } else if (charStack[0] == "#") {
+      // Read the next character to see if it's hex or decimal
+      bool hex = false;
+      charStack.add(stream.char());
+      if (charStack.last == 'x' || charStack.last == 'X') {
+        hex = true;
+        charStack.add(stream.char());
+      }
+
+      // charStack.last should be the first digit
+      if (hex && isHexDigit(charStack.last) ||
+          (!hex && isDigit(charStack.last))) {
+        // At least one digit found, so consume the whole number
+        stream.unget(charStack.last);
+        output = consumeNumberEntity(hex);
+      } else {
+        // No digits found
+        _addToken(new ParseErrorToken("expected-numeric-entity"));
+        stream.unget(charStack.removeLast());
+        output = "&${charStack.join()}";
+      }
+    } else {
+      // At this point in the process might have named entity. Entities
+      // are stored in the global variable "entities".
+      //
+      // Consume characters and compare to these to a substring of the
+      // entity names in the list until the substring no longer matches.
+      var filteredEntityList = entitiesByFirstChar[charStack[0]];
+      if (filteredEntityList == null) filteredEntityList = const [];
+
+      while (charStack.last != EOF) {
+        var name = charStack.join();
+        filteredEntityList = filteredEntityList.where(
+            (e) => e.startsWith(name)).toList();
+
+        if (filteredEntityList.length == 0) {
+          break;
+        }
+        charStack.add(stream.char());
+      }
+
+      // At this point we have a string that starts with some characters
+      // that may match an entity
+      String entityName = null;
+
+      // Try to find the longest entity the string will match to take care
+      // of &noti for instance.
+
+      int entityLen;
+      for (entityLen = charStack.length - 1; entityLen > 1; entityLen--) {
+        var possibleEntityName = charStack.sublist(0, entityLen).join();
+        if (entities.containsKey(possibleEntityName)) {
+          entityName = possibleEntityName;
+          break;
+        }
+      }
+
+      if (entityName != null) {
+        var lastChar = entityName[entityName.length - 1];
+        if (lastChar != ";") {
+          _addToken(new ParseErrorToken(
+              "named-entity-without-semicolon"));
+        }
+        if (lastChar != ";" && fromAttribute &&
+            (isLetterOrDigit(charStack[entityLen]) ||
+             charStack[entityLen] == '=')) {
+          stream.unget(charStack.removeLast());
+          output = "&${charStack.join()}";
+        } else {
+          output = entities[entityName];
+          stream.unget(charStack.removeLast());
+          output = '${output}${slice(charStack, entityLen).join()}';
+        }
+      } else {
+        _addToken(new ParseErrorToken("expected-named-entity"));
+        stream.unget(charStack.removeLast());
+        output = "&${charStack.join()}";
+      }
+    }
+    if (fromAttribute) {
+      _attributeValue = '$_attributeValue$output';
+    } else {
+      var token;
+      if (isWhitespace(output)) {
+        token = new SpaceCharactersToken(output);
+      } else {
+        token = new CharactersToken(output);
+      }
+      _addToken(token);
+    }
+  }
+
+  /** This method replaces the need for "entityInAttributeValueState". */
+  void processEntityInAttribute(String allowedChar) {
+    consumeEntity(allowedChar: allowedChar, fromAttribute: true);
+  }
+
+  /**
+   * This method is a generic handler for emitting the tags. It also sets
+   * the state to "data" because that's what's needed after a token has been
+   * emitted.
+   */
+  void emitCurrentToken() {
+    var token = currentToken;
+    // Add token to the queue to be yielded
+    if (token is TagToken) {
+      if (lowercaseElementName) {
+        token.name = asciiUpper2Lower(token.name);
+      }
+      if (token is EndTagToken) {
+        if (_attributes != null) {
+          _addToken(new ParseErrorToken("attributes-in-end-tag"));
+        }
+        if (token.selfClosing) {
+          _addToken(new ParseErrorToken("this-closing-flag-on-end-tag"));
+        }
+      } else if (token is StartTagToken) {
+        // HTML5 specific normalizations to the token stream.
+        // Convert the list into a map where first key wins.
+        token.data = new LinkedHashMap<Object, String>();
+        if (_attributes != null) {
+          for (var attr in _attributes) {
+            token.data.putIfAbsent(attr.name, () => attr.value);
+          }
+          if (attributeSpans) token.attributeSpans = _attributes;
+        }
+      }
+      _attributes = null;
+      _attributeNames = null;
+    }
+    _addToken(token);
+    state = dataState;
+  }
+
+  // Below are the various tokenizer states worked out.
+
+  bool dataState() {
+    var data = stream.char();
+    if (data == "&") {
+      state = entityDataState;
+    } else if (data == "<") {
+      state = tagOpenState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\u0000"));
+    } else if (data == EOF) {
+      // Tokenization ends.
+      return false;
+    } else if (isWhitespace(data)) {
+      // Directly after emitting a token you switch back to the "data
+      // state". At that point spaceCharacters are important so they are
+      // emitted separately.
+      _addToken(new SpaceCharactersToken(
+          '${data}${stream.charsUntil(spaceCharacters, true)}'));
+      // No need to update lastFourChars here, since the first space will
+      // have already been appended to lastFourChars and will have broken
+      // any <!-- or --> sequences
+    } else {
+      var chars = stream.charsUntil("&<\u0000");
+      _addToken(new CharactersToken('${data}${chars}'));
+    }
+    return true;
+  }
+
+  bool entityDataState() {
+    consumeEntity();
+    state = dataState;
+    return true;
+  }
+
+  bool rcdataState() {
+    var data = stream.char();
+    if (data == "&") {
+      state = characterReferenceInRcdata;
+    } else if (data == "<") {
+      state = rcdataLessThanSignState;
+    } else if (data == EOF) {
+      // Tokenization ends.
+      return false;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+    } else if (isWhitespace(data)) {
+      // Directly after emitting a token you switch back to the "data
+      // state". At that point spaceCharacters are important so they are
+      // emitted separately.
+      _addToken(new SpaceCharactersToken(
+          '${data}${stream.charsUntil(spaceCharacters, true)}'));
+    } else {
+      var chars = stream.charsUntil("&<");
+      _addToken(new CharactersToken('${data}${chars}'));
+    }
+    return true;
+  }
+
+  bool characterReferenceInRcdata() {
+    consumeEntity();
+    state = rcdataState;
+    return true;
+  }
+
+  bool rawtextState() {
+    var data = stream.char();
+    if (data == "<") {
+      state = rawtextLessThanSignState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+    } else if (data == EOF) {
+      // Tokenization ends.
+      return false;
+    } else {
+      var chars = stream.charsUntil("<\u0000");
+      _addToken(new CharactersToken("${data}${chars}"));
+    }
+    return true;
+  }
+
+  bool scriptDataState() {
+    var data = stream.char();
+    if (data == "<") {
+      state = scriptDataLessThanSignState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+    } else if (data == EOF) {
+      // Tokenization ends.
+      return false;
+    } else {
+      var chars = stream.charsUntil("<\u0000");
+      _addToken(new CharactersToken("${data}${chars}"));
+    }
+    return true;
+  }
+
+  bool plaintextState() {
+    var data = stream.char();
+    if (data == EOF) {
+      // Tokenization ends.
+      return false;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+    } else {
+      _addToken(new CharactersToken(
+          '${data}${stream.charsUntil("\u0000")}'));
+    }
+    return true;
+  }
+
+  bool tagOpenState() {
+    var data = stream.char();
+    if (data == "!") {
+      state = markupDeclarationOpenState;
+    } else if (data == "/") {
+      state = closeTagOpenState;
+    } else if (isLetter(data)) {
+      currentToken = new StartTagToken(data);
+      state = tagNameState;
+    } else if (data == ">") {
+      // XXX In theory it could be something besides a tag name. But
+      // do we really care?
+      _addToken(new ParseErrorToken(
+          "expected-tag-name-but-got-right-bracket"));
+      _addToken(new CharactersToken("<>"));
+      state = dataState;
+    } else if (data == "?") {
+      // XXX In theory it could be something besides a tag name. But
+      // do we really care?
+      _addToken(new ParseErrorToken(
+          "expected-tag-name-but-got-question-mark"));
+      stream.unget(data);
+      state = bogusCommentState;
+    } else {
+      // XXX
+      _addToken(new ParseErrorToken("expected-tag-name"));
+      _addToken(new CharactersToken("<"));
+      stream.unget(data);
+      state = dataState;
+    }
+    return true;
+  }
+
+  bool closeTagOpenState() {
+    var data = stream.char();
+    if (isLetter(data)) {
+      currentToken = new EndTagToken(data);
+      state = tagNameState;
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken(
+          "expected-closing-tag-but-got-right-bracket"));
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken(
+          "expected-closing-tag-but-got-eof"));
+      _addToken(new CharactersToken("</"));
+      state = dataState;
+    } else {
+      // XXX data can be _'_...
+      _addToken(new ParseErrorToken(
+          "expected-closing-tag-but-got-char", messageParams: {"data": data}));
+      stream.unget(data);
+      state = bogusCommentState;
+    }
+    return true;
+  }
+
+  bool tagNameState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      state = beforeAttributeNameState;
+    } else if (data == ">") {
+      emitCurrentToken();
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-tag-name"));
+      state = dataState;
+    } else if (data == "/") {
+      state = selfClosingStartTagState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentTagToken.name = '${currentTagToken.name}\uFFFD';
+    } else {
+      currentTagToken.name = '${currentTagToken.name}$data';
+      // (Don't use charsUntil here, because tag names are
+      // very short and it's faster to not do anything fancy)
+    }
+    return true;
+  }
+
+  bool rcdataLessThanSignState() {
+    var data = stream.char();
+    if (data == "/") {
+      temporaryBuffer = "";
+      state = rcdataEndTagOpenState;
+    } else {
+      _addToken(new CharactersToken("<"));
+      stream.unget(data);
+      state = rcdataState;
+    }
+    return true;
+  }
+
+  bool rcdataEndTagOpenState() {
+    var data = stream.char();
+    if (isLetter(data)) {
+      temporaryBuffer = '${temporaryBuffer}$data';
+      state = rcdataEndTagNameState;
+    } else {
+      _addToken(new CharactersToken("</"));
+      stream.unget(data);
+      state = rcdataState;
+    }
+    return true;
+  }
+
+  bool _tokenIsAppropriate() {
+    return currentToken is TagToken &&
+        currentTagToken.name.toLowerCase() == temporaryBuffer.toLowerCase();
+  }
+
+  bool rcdataEndTagNameState() {
+    var appropriate = _tokenIsAppropriate();
+    var data = stream.char();
+    if (isWhitespace(data) && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = beforeAttributeNameState;
+    } else if (data == "/" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = selfClosingStartTagState;
+    } else if (data == ">" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      emitCurrentToken();
+      state = dataState;
+    } else if (isLetter(data)) {
+      temporaryBuffer = '${temporaryBuffer}$data';
+    } else {
+      _addToken(new CharactersToken("</$temporaryBuffer"));
+      stream.unget(data);
+      state = rcdataState;
+    }
+    return true;
+  }
+
+  bool rawtextLessThanSignState() {
+    var data = stream.char();
+    if (data == "/") {
+      temporaryBuffer = "";
+      state = rawtextEndTagOpenState;
+    } else {
+      _addToken(new CharactersToken("<"));
+      stream.unget(data);
+      state = rawtextState;
+    }
+    return true;
+  }
+
+  bool rawtextEndTagOpenState() {
+    var data = stream.char();
+    if (isLetter(data)) {
+      temporaryBuffer = '${temporaryBuffer}$data';
+      state = rawtextEndTagNameState;
+    } else {
+      _addToken(new CharactersToken("</"));
+      stream.unget(data);
+      state = rawtextState;
+    }
+    return true;
+  }
+
+  bool rawtextEndTagNameState() {
+    var appropriate = _tokenIsAppropriate();
+    var data = stream.char();
+    if (isWhitespace(data) && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = beforeAttributeNameState;
+    } else if (data == "/" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = selfClosingStartTagState;
+    } else if (data == ">" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      emitCurrentToken();
+      state = dataState;
+    } else if (isLetter(data)) {
+      temporaryBuffer = '${temporaryBuffer}$data';
+    } else {
+      _addToken(new CharactersToken("</$temporaryBuffer"));
+      stream.unget(data);
+      state = rawtextState;
+    }
+    return true;
+  }
+
+  bool scriptDataLessThanSignState() {
+    var data = stream.char();
+    if (data == "/") {
+      temporaryBuffer = "";
+      state = scriptDataEndTagOpenState;
+    } else if (data == "!") {
+      _addToken(new CharactersToken("<!"));
+      state = scriptDataEscapeStartState;
+    } else {
+      _addToken(new CharactersToken("<"));
+      stream.unget(data);
+      state = scriptDataState;
+    }
+    return true;
+  }
+
+  bool scriptDataEndTagOpenState() {
+    var data = stream.char();
+    if (isLetter(data)) {
+      temporaryBuffer = '${temporaryBuffer}$data';
+      state = scriptDataEndTagNameState;
+    } else {
+      _addToken(new CharactersToken("</"));
+      stream.unget(data);
+      state = scriptDataState;
+    }
+    return true;
+  }
+
+  bool scriptDataEndTagNameState() {
+    var appropriate = _tokenIsAppropriate();
+    var data = stream.char();
+    if (isWhitespace(data) && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = beforeAttributeNameState;
+    } else if (data == "/" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = selfClosingStartTagState;
+    } else if (data == ">" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      emitCurrentToken();
+      state = dataState;
+    } else if (isLetter(data)) {
+      temporaryBuffer = '${temporaryBuffer}$data';
+    } else {
+      _addToken(new CharactersToken("</$temporaryBuffer"));
+      stream.unget(data);
+      state = scriptDataState;
+    }
+    return true;
+  }
+
+  bool scriptDataEscapeStartState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+      state = scriptDataEscapeStartDashState;
+    } else {
+      stream.unget(data);
+      state = scriptDataState;
+    }
+    return true;
+  }
+
+  bool scriptDataEscapeStartDashState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+      state = scriptDataEscapedDashDashState;
+    } else {
+      stream.unget(data);
+      state = scriptDataState;
+    }
+    return true;
+  }
+
+  bool scriptDataEscapedState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+      state = scriptDataEscapedDashState;
+    } else if (data == "<") {
+      state = scriptDataEscapedLessThanSignState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+    } else if (data == EOF) {
+      state = dataState;
+    } else {
+      var chars = stream.charsUntil("<-\u0000");
+      _addToken(new CharactersToken("${data}${chars}"));
+    }
+    return true;
+  }
+
+  bool scriptDataEscapedDashState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+      state = scriptDataEscapedDashDashState;
+    } else if (data == "<") {
+      state = scriptDataEscapedLessThanSignState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+      state = scriptDataEscapedState;
+    } else if (data == EOF) {
+      state = dataState;
+    } else {
+      _addToken(new CharactersToken(data));
+      state = scriptDataEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataEscapedDashDashState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+    } else if (data == "<") {
+      state = scriptDataEscapedLessThanSignState;
+    } else if (data == ">") {
+      _addToken(new CharactersToken(">"));
+      state = scriptDataState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+      state = scriptDataEscapedState;
+    } else if (data == EOF) {
+      state = dataState;
+    } else {
+      _addToken(new CharactersToken(data));
+      state = scriptDataEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataEscapedLessThanSignState() {
+    var data = stream.char();
+    if (data == "/") {
+      temporaryBuffer = "";
+      state = scriptDataEscapedEndTagOpenState;
+    } else if (isLetter(data)) {
+      _addToken(new CharactersToken("<$data"));
+      temporaryBuffer = data;
+      state = scriptDataDoubleEscapeStartState;
+    } else {
+      _addToken(new CharactersToken("<"));
+      stream.unget(data);
+      state = scriptDataEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataEscapedEndTagOpenState() {
+    var data = stream.char();
+    if (isLetter(data)) {
+      temporaryBuffer = data;
+      state = scriptDataEscapedEndTagNameState;
+    } else {
+      _addToken(new CharactersToken("</"));
+      stream.unget(data);
+      state = scriptDataEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataEscapedEndTagNameState() {
+    var appropriate = _tokenIsAppropriate();
+    var data = stream.char();
+    if (isWhitespace(data) && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = beforeAttributeNameState;
+    } else if (data == "/" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      state = selfClosingStartTagState;
+    } else if (data == ">" && appropriate) {
+      currentToken = new EndTagToken(temporaryBuffer);
+      emitCurrentToken();
+      state = dataState;
+    } else if (isLetter(data)) {
+      temporaryBuffer = '${temporaryBuffer}$data';
+    } else {
+      _addToken(new CharactersToken("</$temporaryBuffer"));
+      stream.unget(data);
+      state = scriptDataEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataDoubleEscapeStartState() {
+    var data = stream.char();
+    if (isWhitespace(data) || data == "/" || data == ">") {
+      _addToken(new CharactersToken(data));
+      if (temporaryBuffer.toLowerCase() == "script") {
+        state = scriptDataDoubleEscapedState;
+      } else {
+        state = scriptDataEscapedState;
+      }
+    } else if (isLetter(data)) {
+      _addToken(new CharactersToken(data));
+      temporaryBuffer = '${temporaryBuffer}$data';
+    } else {
+      stream.unget(data);
+      state = scriptDataEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataDoubleEscapedState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+      state = scriptDataDoubleEscapedDashState;
+    } else if (data == "<") {
+      _addToken(new CharactersToken("<"));
+      state = scriptDataDoubleEscapedLessThanSignState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-script-in-script"));
+      state = dataState;
+    } else {
+      _addToken(new CharactersToken(data));
+    }
+    return true;
+  }
+
+  bool scriptDataDoubleEscapedDashState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+      state = scriptDataDoubleEscapedDashDashState;
+    } else if (data == "<") {
+      _addToken(new CharactersToken("<"));
+      state = scriptDataDoubleEscapedLessThanSignState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+      state = scriptDataDoubleEscapedState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-script-in-script"));
+      state = dataState;
+    } else {
+      _addToken(new CharactersToken(data));
+      state = scriptDataDoubleEscapedState;
+    }
+    return true;
+  }
+
+  // TODO(jmesserly): report bug in original code
+  // (was "Dash" instead of "DashDash")
+  bool scriptDataDoubleEscapedDashDashState() {
+    var data = stream.char();
+    if (data == "-") {
+      _addToken(new CharactersToken("-"));
+    } else if (data == "<") {
+      _addToken(new CharactersToken("<"));
+      state = scriptDataDoubleEscapedLessThanSignState;
+    } else if (data == ">") {
+      _addToken(new CharactersToken(">"));
+      state = scriptDataState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addToken(new CharactersToken("\uFFFD"));
+      state = scriptDataDoubleEscapedState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-script-in-script"));
+      state = dataState;
+    } else {
+      _addToken(new CharactersToken(data));
+      state = scriptDataDoubleEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataDoubleEscapedLessThanSignState() {
+    var data = stream.char();
+    if (data == "/") {
+      _addToken(new CharactersToken("/"));
+      temporaryBuffer = "";
+      state = scriptDataDoubleEscapeEndState;
+    } else {
+      stream.unget(data);
+      state = scriptDataDoubleEscapedState;
+    }
+    return true;
+  }
+
+  bool scriptDataDoubleEscapeEndState() {
+    var data = stream.char();
+    if (isWhitespace(data) || data == "/" || data == ">") {
+      _addToken(new CharactersToken(data));
+      if (temporaryBuffer.toLowerCase() == "script") {
+        state = scriptDataEscapedState;
+      } else {
+        state = scriptDataDoubleEscapedState;
+      }
+    } else if (isLetter(data)) {
+      _addToken(new CharactersToken(data));
+      temporaryBuffer = '${temporaryBuffer}$data';
+    } else {
+      stream.unget(data);
+      state = scriptDataDoubleEscapedState;
+    }
+    return true;
+  }
+
+  bool beforeAttributeNameState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      stream.charsUntil(spaceCharacters, true);
+    } else if (isLetter(data)) {
+      _addAttribute(data);
+      state = attributeNameState;
+    } else if (data == ">") {
+      emitCurrentToken();
+    } else if (data == "/") {
+      state = selfClosingStartTagState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("expected-attribute-name-but-got-eof"));
+      state = dataState;
+    } else if ("'\"=<".contains(data)) {
+      _addToken(new ParseErrorToken("invalid-character-in-attribute-name"));
+      _addAttribute(data);
+      state = attributeNameState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addAttribute("\uFFFD");
+      state = attributeNameState;
+    } else {
+      _addAttribute(data);
+      state = attributeNameState;
+    }
+    return true;
+  }
+
+  bool attributeNameState() {
+    var data = stream.char();
+    bool leavingThisState = true;
+    bool emitToken = false;
+    if (data == "=") {
+      state = beforeAttributeValueState;
+    } else if (isLetter(data)) {
+      _attributeName = '$_attributeName$data'
+          '${stream.charsUntil(asciiLetters, true)}';
+      leavingThisState = false;
+    } else if (data == ">") {
+      // XXX If we emit here the attributes are converted to a dict
+      // without being checked and when the code below runs we error
+      // because data is a dict not a list
+      emitToken = true;
+    } else if (isWhitespace(data)) {
+      state = afterAttributeNameState;
+    } else if (data == "/") {
+      state = selfClosingStartTagState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _attributeName = '${_attributeName}\uFFFD';
+      leavingThisState = false;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-attribute-name"));
+      state = dataState;
+    } else if ("'\"<".contains(data)) {
+      _addToken(new ParseErrorToken("invalid-character-in-attribute-name"));
+      _attributeName = '$_attributeName$data';
+      leavingThisState = false;
+    } else {
+      _attributeName = '$_attributeName$data';
+      leavingThisState = false;
+    }
+
+    if (leavingThisState) {
+      _markAttributeNameEnd(-1);
+
+      // Attributes are not dropped at this stage. That happens when the
+      // start tag token is emitted so values can still be safely appended
+      // to attributes, but we do want to report the parse error in time.
+      if (lowercaseAttrName) {
+        _attributeName = asciiUpper2Lower(_attributeName);
+      }
+      if (_attributeNames == null) _attributeNames = new Set();
+      if (_attributeNames.contains(_attributeName)) {
+        _addToken(new ParseErrorToken("duplicate-attribute"));
+      }
+      _attributeNames.add(_attributeName);
+
+      // XXX Fix for above XXX
+      if (emitToken) {
+        emitCurrentToken();
+      }
+    }
+    return true;
+  }
+
+  bool afterAttributeNameState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      stream.charsUntil(spaceCharacters, true);
+    } else if (data == "=") {
+      state = beforeAttributeValueState;
+    } else if (data == ">") {
+      emitCurrentToken();
+    } else if (isLetter(data)) {
+      _addAttribute(data);
+      state = attributeNameState;
+    } else if (data == "/") {
+      state = selfClosingStartTagState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _addAttribute("\uFFFD");
+      state = attributeNameState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("expected-end-of-tag-but-got-eof"));
+      state = dataState;
+    } else if ("'\"<".contains(data)) {
+      _addToken(new ParseErrorToken("invalid-character-after-attribute-name"));
+      _addAttribute(data);
+      state = attributeNameState;
+    } else {
+      _addAttribute(data);
+      state = attributeNameState;
+    }
+    return true;
+  }
+
+  bool beforeAttributeValueState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      stream.charsUntil(spaceCharacters, true);
+    } else if (data == "\"") {
+      _markAttributeValueStart(0);
+      state = attributeValueDoubleQuotedState;
+    } else if (data == "&") {
+      state = attributeValueUnQuotedState;
+      stream.unget(data);
+      _markAttributeValueStart(0);
+    } else if (data == "'") {
+      _markAttributeValueStart(0);
+      state = attributeValueSingleQuotedState;
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken(
+          "expected-attribute-value-but-got-right-bracket"));
+      emitCurrentToken();
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _markAttributeValueStart(-1);
+      _attributeValue = '${_attributeValue}\uFFFD';
+      state = attributeValueUnQuotedState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("expected-attribute-value-but-got-eof"));
+      state = dataState;
+    } else if ("=<`".contains(data)) {
+      _addToken(new ParseErrorToken("equals-in-unquoted-attribute-value"));
+      _markAttributeValueStart(-1);
+      _attributeValue = '$_attributeValue$data';
+      state = attributeValueUnQuotedState;
+    } else {
+      _markAttributeValueStart(-1);
+      _attributeValue = '$_attributeValue$data';
+      state = attributeValueUnQuotedState;
+    }
+    return true;
+  }
+
+  bool attributeValueDoubleQuotedState() {
+    var data = stream.char();
+    if (data == "\"") {
+      _markAttributeValueEnd(-1);
+      _markAttributeEnd(0);
+      state = afterAttributeValueState;
+    } else if (data == "&") {
+      processEntityInAttribute('"');
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _attributeValue = '${_attributeValue}\uFFFD';
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-attribute-value-double-quote"));
+      _markAttributeValueEnd(-1);
+      state = dataState;
+    } else {
+      _attributeValue = '$_attributeValue$data${stream.charsUntil("\"&")}';
+    }
+    return true;
+  }
+
+  bool attributeValueSingleQuotedState() {
+    var data = stream.char();
+    if (data == "'") {
+      _markAttributeValueEnd(-1);
+      _markAttributeEnd(0);
+      state = afterAttributeValueState;
+    } else if (data == "&") {
+      processEntityInAttribute("'");
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _attributeValue = '${_attributeValue}\uFFFD';
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-attribute-value-single-quote"));
+      _markAttributeValueEnd(-1);
+      state = dataState;
+    } else {
+      _attributeValue = '$_attributeValue$data${stream.charsUntil("\'&")}';
+    }
+    return true;
+  }
+
+  bool attributeValueUnQuotedState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      _markAttributeValueEnd(-1);
+      state = beforeAttributeNameState;
+    } else if (data == "&") {
+      processEntityInAttribute(">");
+    } else if (data == ">") {
+      _markAttributeValueEnd(-1);
+      emitCurrentToken();
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-attribute-value-no-quotes"));
+      _markAttributeValueEnd(-1);
+      state = dataState;
+    } else if ('"\'=<`'.contains(data)) {
+      _addToken(new ParseErrorToken(
+          "unexpected-character-in-unquoted-attribute-value"));
+      _attributeValue = '$_attributeValue$data';
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      _attributeValue = '${_attributeValue}\uFFFD';
+    } else {
+      _attributeValue = '$_attributeValue$data'
+          '${stream.charsUntil("&>\"\'=<`$spaceCharacters")}';
+    }
+    return true;
+  }
+
+  bool afterAttributeValueState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      state = beforeAttributeNameState;
+    } else if (data == ">") {
+      emitCurrentToken();
+    } else if (data == "/") {
+      state = selfClosingStartTagState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("unexpected-EOF-after-attribute-value"));
+      stream.unget(data);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken(
+          "unexpected-character-after-attribute-value"));
+      stream.unget(data);
+      state = beforeAttributeNameState;
+    }
+    return true;
+  }
+
+  bool selfClosingStartTagState() {
+    var data = stream.char();
+    if (data == ">") {
+      currentTagToken.selfClosing = true;
+      emitCurrentToken();
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("unexpected-EOF-after-solidus-in-tag"));
+      stream.unget(data);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken(
+          "unexpected-character-after-soldius-in-tag"));
+      stream.unget(data);
+      state = beforeAttributeNameState;
+    }
+    return true;
+  }
+
+  bool bogusCommentState() {
+    // Make a new comment token and give it as value all the characters
+    // until the first > or EOF (charsUntil checks for EOF automatically)
+    // and emit it.
+    var data = stream.charsUntil(">");
+    data = data.replaceAll("\u0000", "\uFFFD");
+    _addToken(new CommentToken(data));
+
+    // Eat the character directly after the bogus comment which is either a
+    // ">" or an EOF.
+    stream.char();
+    state = dataState;
+    return true;
+  }
+
+  bool markupDeclarationOpenState() {
+    var charStack = [stream.char()];
+    if (charStack.last == "-") {
+      charStack.add(stream.char());
+      if (charStack.last == "-") {
+        currentToken = new CommentToken("");
+        state = commentStartState;
+        return true;
+      }
+    } else if (charStack.last == 'd' || charStack.last == 'D') {
+      var matched = true;
+      for (var expected in const ['oO', 'cC', 'tT', 'yY', 'pP', 'eE']) {
+        var char = stream.char();
+        charStack.add(char);
+        if (char == EOF || !expected.contains(char)) {
+          matched = false;
+          break;
+        }
+      }
+      if (matched) {
+        currentToken = new DoctypeToken(correct: true);
+        state = doctypeState;
+        return true;
+      }
+    } else if (charStack.last == "[" &&
+        parser != null && parser.tree.openElements.length > 0 &&
+        parser.tree.openElements.last.namespace
+            != parser.tree.defaultNamespace) {
+      var matched = true;
+      for (var expected in const ["C", "D", "A", "T", "A", "["]) {
+        charStack.add(stream.char());
+        if (charStack.last != expected) {
+          matched = false;
+          break;
+        }
+      }
+      if (matched) {
+        state = cdataSectionState;
+        return true;
+      }
+    }
+
+    _addToken(new ParseErrorToken("expected-dashes-or-doctype"));
+
+    while (charStack.length > 0) {
+      stream.unget(charStack.removeLast());
+    }
+    state = bogusCommentState;
+    return true;
+  }
+
+  bool commentStartState() {
+    var data = stream.char();
+    if (data == "-") {
+      state = commentStartDashState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentStringToken.data = '${currentStringToken.data}\uFFFD';
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("incorrect-comment"));
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-comment"));
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentStringToken.data = '${currentStringToken.data}$data';
+      state = commentState;
+    }
+    return true;
+  }
+
+  bool commentStartDashState() {
+    var data = stream.char();
+    if (data == "-") {
+      state = commentEndState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentStringToken.data = '${currentStringToken.data}-\uFFFD';
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("incorrect-comment"));
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-comment"));
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentStringToken.data = '${currentStringToken.data}-${data}';
+      state = commentState;
+    }
+    return true;
+  }
+
+  bool commentState() {
+    var data = stream.char();
+    if (data == "-") {
+      state = commentEndDashState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentStringToken.data = '${currentStringToken.data}\uFFFD';
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-comment"));
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentStringToken.data = '${currentStringToken.data}$data'
+          '${stream.charsUntil("-\u0000")}';
+    }
+    return true;
+  }
+
+  bool commentEndDashState() {
+    var data = stream.char();
+    if (data == "-") {
+      state = commentEndState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentStringToken.data = "${currentStringToken.data}-\uFFFD";
+      state = commentState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-comment-end-dash"));
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentStringToken.data = "${currentStringToken.data}-${data}";
+      state = commentState;
+    }
+    return true;
+  }
+
+  bool commentEndState() {
+    var data = stream.char();
+    if (data == ">") {
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentStringToken.data = '${currentStringToken.data}--\uFFFD';
+      state = commentState;
+    } else if (data == "!") {
+      _addToken(new ParseErrorToken(
+          "unexpected-bang-after-double-dash-in-comment"));
+      state = commentEndBangState;
+    } else if (data == "-") {
+      _addToken(new ParseErrorToken(
+          "unexpected-dash-after-double-dash-in-comment"));
+      currentStringToken.data = '${currentStringToken.data}$data';
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-comment-double-dash"));
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      // XXX
+      _addToken(new ParseErrorToken("unexpected-char-in-comment"));
+      currentStringToken.data = "${currentStringToken.data}--${data}";
+      state = commentState;
+    }
+    return true;
+  }
+
+  bool commentEndBangState() {
+    var data = stream.char();
+    if (data == ">") {
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == "-") {
+      currentStringToken.data = '${currentStringToken.data}--!';
+      state = commentEndDashState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentStringToken.data = '${currentStringToken.data}--!\uFFFD';
+      state = commentState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-comment-end-bang-state"));
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentStringToken.data = "${currentStringToken.data}--!${data}";
+      state = commentState;
+    }
+    return true;
+  }
+
+  bool doctypeState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      state = beforeDoctypeNameState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken(
+          "expected-doctype-name-but-got-eof"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken("need-space-after-doctype"));
+      stream.unget(data);
+      state = beforeDoctypeNameState;
+    }
+    return true;
+  }
+
+  bool beforeDoctypeNameState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      return true;
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken(
+          "expected-doctype-name-but-got-right-bracket"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.name = "\uFFFD";
+      state = doctypeNameState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken(
+          "expected-doctype-name-but-got-eof"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentDoctypeToken.name = data;
+      state = doctypeNameState;
+    }
+    return true;
+  }
+
+  bool doctypeNameState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      currentDoctypeToken.name = asciiUpper2Lower(currentDoctypeToken.name);
+      state = afterDoctypeNameState;
+    } else if (data == ">") {
+      currentDoctypeToken.name = asciiUpper2Lower(currentDoctypeToken.name);
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.name = "${currentDoctypeToken.name}\uFFFD";
+      state = doctypeNameState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype-name"));
+      currentDoctypeToken.correct = false;
+      currentDoctypeToken.name = asciiUpper2Lower(currentDoctypeToken.name);
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentDoctypeToken.name = '${currentDoctypeToken.name}$data';
+    }
+    return true;
+  }
+
+  bool afterDoctypeNameState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      return true;
+    } else if (data == ">") {
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      currentDoctypeToken.correct = false;
+      stream.unget(data);
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      if (data == "p" || data == "P") {
+        // TODO(jmesserly): would be nice to have a helper for this.
+        var matched = true;
+        for (var expected in const ["uU", "bB", "lL", "iI", "cC"]) {
+          data = stream.char();
+          if (data == EOF || !expected.contains(data)) {
+            matched = false;
+            break;
+          }
+        }
+        if (matched) {
+          state = afterDoctypePublicKeywordState;
+          return true;
+        }
+      } else if (data == "s" || data == "S") {
+        var matched = true;
+        for (var expected in const ["yY", "sS", "tT", "eE", "mM"]) {
+          data = stream.char();
+          if (data == EOF || !expected.contains(data)) {
+            matched = false;
+            break;
+          }
+        }
+        if (matched) {
+          state = afterDoctypeSystemKeywordState;
+          return true;
+        }
+      }
+
+      // All the characters read before the current 'data' will be
+      // [a-zA-Z], so they're garbage in the bogus doctype and can be
+      // discarded; only the latest character might be '>' or EOF
+      // and needs to be ungetted
+      stream.unget(data);
+      _addToken(new ParseErrorToken(
+          "expected-space-or-right-bracket-in-doctype",
+          messageParams: {"data": data}));
+      currentDoctypeToken.correct = false;
+      state = bogusDoctypeState;
+    }
+    return true;
+  }
+
+  bool afterDoctypePublicKeywordState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      state = beforeDoctypePublicIdentifierState;
+    } else if (data == "'" || data == '"') {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      stream.unget(data);
+      state = beforeDoctypePublicIdentifierState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      stream.unget(data);
+      state = beforeDoctypePublicIdentifierState;
+    }
+    return true;
+  }
+
+  bool beforeDoctypePublicIdentifierState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      return true;
+    } else if (data == "\"") {
+      currentDoctypeToken.publicId = "";
+      state = doctypePublicIdentifierDoubleQuotedState;
+    } else if (data == "'") {
+      currentDoctypeToken.publicId = "";
+      state = doctypePublicIdentifierSingleQuotedState;
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("unexpected-end-of-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.correct = false;
+      state = bogusDoctypeState;
+    }
+    return true;
+  }
+
+  bool doctypePublicIdentifierDoubleQuotedState() {
+    var data = stream.char();
+    if (data == '"') {
+      state = afterDoctypePublicIdentifierState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.publicId = "${currentDoctypeToken.publicId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("unexpected-end-of-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}$data';
+    }
+    return true;
+  }
+
+  bool doctypePublicIdentifierSingleQuotedState() {
+    var data = stream.char();
+    if (data == "'") {
+      state = afterDoctypePublicIdentifierState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.publicId = "${currentDoctypeToken.publicId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("unexpected-end-of-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}$data';
+    }
+    return true;
+  }
+
+  bool afterDoctypePublicIdentifierState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      state = betweenDoctypePublicAndSystemIdentifiersState;
+    } else if (data == ">") {
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == '"') {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.systemId = "";
+      state = doctypeSystemIdentifierDoubleQuotedState;
+    } else if (data == "'") {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.systemId = "";
+      state = doctypeSystemIdentifierSingleQuotedState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.correct = false;
+      state = bogusDoctypeState;
+    }
+    return true;
+  }
+
+  bool betweenDoctypePublicAndSystemIdentifiersState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      return true;
+    } else if (data == ">") {
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == '"') {
+      currentDoctypeToken.systemId = "";
+      state = doctypeSystemIdentifierDoubleQuotedState;
+    } else if (data == "'") {
+      currentDoctypeToken.systemId = "";
+      state = doctypeSystemIdentifierSingleQuotedState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.correct = false;
+      state = bogusDoctypeState;
+    }
+    return true;
+  }
+
+  bool afterDoctypeSystemKeywordState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      state = beforeDoctypeSystemIdentifierState;
+    } else if (data == "'" || data == '"') {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      stream.unget(data);
+      state = beforeDoctypeSystemIdentifierState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      stream.unget(data);
+      state = beforeDoctypeSystemIdentifierState;
+    }
+    return true;
+  }
+
+  bool beforeDoctypeSystemIdentifierState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      return true;
+    } else if (data == "\"") {
+      currentDoctypeToken.systemId = "";
+      state = doctypeSystemIdentifierDoubleQuotedState;
+    } else if (data == "'") {
+      currentDoctypeToken.systemId = "";
+      state = doctypeSystemIdentifierSingleQuotedState;
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.correct = false;
+      state = bogusDoctypeState;
+    }
+    return true;
+  }
+
+  bool doctypeSystemIdentifierDoubleQuotedState() {
+    var data = stream.char();
+    if (data == "\"") {
+      state = afterDoctypeSystemIdentifierState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.systemId = "${currentDoctypeToken.systemId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("unexpected-end-of-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}$data';
+    }
+    return true;
+  }
+
+  bool doctypeSystemIdentifierSingleQuotedState() {
+    var data = stream.char();
+    if (data == "'") {
+      state = afterDoctypeSystemIdentifierState;
+    } else if (data == "\u0000") {
+      _addToken(new ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.systemId = "${currentDoctypeToken.systemId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(new ParseErrorToken("unexpected-end-of-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}$data';
+    }
+    return true;
+  }
+
+  bool afterDoctypeSystemIdentifierState() {
+    var data = stream.char();
+    if (isWhitespace(data)) {
+      return true;
+    } else if (data == ">") {
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      _addToken(new ParseErrorToken("eof-in-doctype"));
+      currentDoctypeToken.correct = false;
+      _addToken(currentToken);
+      state = dataState;
+    } else {
+      _addToken(new ParseErrorToken("unexpected-char-in-doctype"));
+      state = bogusDoctypeState;
+    }
+    return true;
+  }
+
+  bool bogusDoctypeState() {
+    var data = stream.char();
+    if (data == ">") {
+      _addToken(currentToken);
+      state = dataState;
+    } else if (data == EOF) {
+      // XXX EMIT
+      stream.unget(data);
+      _addToken(currentToken);
+      state = dataState;
+    }
+    return true;
+  }
+
+  bool cdataSectionState() {
+    var data = [];
+    int matchedEnd = 0;
+    while (true) {
+      var ch = stream.char();
+      if (ch == EOF) {
+        break;
+      }
+      // Deal with null here rather than in the parser
+      if (ch == "\u0000") {
+        _addToken(new ParseErrorToken("invalid-codepoint"));
+        ch = "\uFFFD";
+      }
+      data.add(ch);
+      // TODO(jmesserly): it'd be nice if we had an easier way to match the end,
+      // perhaps with a "peek" API.
+      if (ch == "]" && matchedEnd < 2) {
+        matchedEnd++;
+      } else if (ch == ">" && matchedEnd == 2) {
+        // Remove "]]>" from the end.
+        data.removeLast();
+        data.removeLast();
+        data.removeLast();
+        break;
+      } else {
+        matchedEnd = 0;
+      }
+    }
+
+    if (data.length > 0) {
+      _addToken(new CharactersToken(data.join()));
+    }
+    state = dataState;
+    return true;
+  }
+}
+
diff --git a/pkg/third_party/html5lib/lib/src/treebuilder.dart b/pkg/third_party/html5lib/lib/src/treebuilder.dart
new file mode 100644
index 0000000..bb53d58
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/treebuilder.dart
@@ -0,0 +1,400 @@
+/** Internals to the tree builders. */
+library treebuilder;
+
+import 'dart:collection';
+import 'package:html5lib/dom.dart';
+import 'package:source_maps/span.dart' show FileSpan;
+import 'constants.dart';
+import 'list_proxy.dart';
+import 'token.dart';
+import 'utils.dart';
+
+// The scope markers are inserted when entering object elements,
+// marquees, table cells, and table captions, and are used to prevent formatting
+// from "leaking" into tables, object elements, and marquees.
+final Node Marker = null;
+
+// TODO(jmesserly): this should extend ListBase<Node>, but my simple attempt
+// didn't work.
+class ActiveFormattingElements extends ListProxy<Node> {
+  ActiveFormattingElements() : super();
+
+  // Override the "add" method.
+  // TODO(jmesserly): I'd rather not override this; can we do this in the
+  // calling code instead?
+  void add(Node node) {
+    int equalCount = 0;
+    if (node != Marker) {
+      for (Node element in reversed) {
+        if (element == Marker) {
+          break;
+        }
+        if (_nodesEqual(element, node)) {
+          equalCount += 1;
+        }
+        if (equalCount == 3) {
+          remove(element);
+          break;
+        }
+      }
+    }
+    super.add(node);
+  }
+}
+
+// TODO(jmesserly): this should exist in corelib...
+bool _mapEquals(Map a, Map b) {
+  if (a.length != b.length) return false;
+  if (a.length == 0) return true;
+
+  for (var keyA in a.keys) {
+    var valB = b[keyA];
+    if (valB == null && !b.containsKey(keyA)) {
+      return false;
+    }
+
+    if (a[keyA] != valB) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+bool _nodesEqual(Node node1, Node node2) {
+  return node1.nameTuple == node2.nameTuple &&
+      _mapEquals(node1.attributes, node2.attributes);
+}
+
+/** Basic treebuilder implementation. */
+class TreeBuilder {
+  final String defaultNamespace;
+
+  Document document;
+
+  final openElements = <Node>[];
+
+  final activeFormattingElements = new ActiveFormattingElements();
+
+  Node headPointer;
+
+  Node formPointer;
+
+  /**
+   * Switch the function used to insert an element from the
+   * normal one to the misnested table one and back again
+   */
+  bool insertFromTable;
+
+  TreeBuilder(bool namespaceHTMLElements)
+      : defaultNamespace = namespaceHTMLElements ? Namespaces.html : null {
+    reset();
+  }
+
+  void reset() {
+    openElements.clear();
+    activeFormattingElements.clear();
+
+    //XXX - rename these to headElement, formElement
+    headPointer = null;
+    formPointer = null;
+
+    insertFromTable = false;
+
+    document = new Document();
+  }
+
+  bool elementInScope(target, {String variant}) {
+    //If we pass a node in we match that. if we pass a string
+    //match any node with that name
+    bool exactNode = target is Node && target.nameTuple != null;
+
+    List listElements1 = scopingElements;
+    List listElements2 = const [];
+    bool invert = false;
+    if (variant != null) {
+      switch (variant) {
+        case "button":
+          listElements2 = const [const Pair(Namespaces.html, "button")];
+          break;
+        case "list":
+          listElements2 = const [const Pair(Namespaces.html, "ol"),
+                                 const Pair(Namespaces.html, "ul")];
+          break;
+        case "table":
+          listElements1 = const [const Pair(Namespaces.html, "html"),
+                                 const Pair(Namespaces.html, "table")];
+          break;
+        case "select":
+          listElements1 = const [const Pair(Namespaces.html, "optgroup"),
+                                 const Pair(Namespaces.html, "option")];
+          invert = true;
+          break;
+        default: assert(false); break;
+      }
+    }
+
+    for (Node node in openElements.reversed) {
+      if (node.tagName == target && !exactNode ||
+          node == target && exactNode) {
+        return true;
+      } else if (invert !=
+          (listElements1.contains(node.nameTuple) ||
+           listElements2.contains(node.nameTuple))) {
+        return false;
+      }
+    }
+
+    assert(false); // We should never reach this point
+  }
+
+  void reconstructActiveFormattingElements() {
+    // Within this algorithm the order of steps described in the
+    // specification is not quite the same as the order of steps in the
+    // code. It should still do the same though.
+
+    // Step 1: stop the algorithm when there's nothing to do.
+    if (activeFormattingElements.length == 0) {
+      return;
+    }
+
+    // Step 2 and step 3: we start with the last element. So i is -1.
+    int i = activeFormattingElements.length - 1;
+    var entry = activeFormattingElements[i];
+    if (entry == Marker || openElements.contains(entry)) {
+      return;
+    }
+
+    // Step 6
+    while (entry != Marker && !openElements.contains(entry)) {
+      if (i == 0) {
+        //This will be reset to 0 below
+        i = -1;
+        break;
+      }
+      i -= 1;
+      // Step 5: let entry be one earlier in the list.
+      entry = activeFormattingElements[i];
+    }
+
+    while (true) {
+      // Step 7
+      i += 1;
+
+      // Step 8
+      entry = activeFormattingElements[i];
+
+      // TODO(jmesserly): optimize this. No need to create a token.
+      var cloneToken = new StartTagToken(
+          entry.tagName,
+          namespace: entry.namespace,
+          data: new LinkedHashMap.from(entry.attributes))
+          ..span = entry.sourceSpan;
+
+      // Step 9
+      var element = insertElement(cloneToken);
+
+      // Step 10
+      activeFormattingElements[i] = element;
+
+      // Step 11
+      if (element == activeFormattingElements.last) {
+        break;
+      }
+    }
+  }
+
+  void clearActiveFormattingElements() {
+    var entry = activeFormattingElements.removeLast();
+    while (activeFormattingElements.length > 0 && entry != Marker) {
+      entry = activeFormattingElements.removeLast();
+    }
+  }
+
+  /**
+   * Check if an element exists between the end of the active
+   * formatting elements and the last marker. If it does, return it, else
+   * return null.
+   */
+  Node elementInActiveFormattingElements(String name) {
+    for (Node item in activeFormattingElements.reversed) {
+      // Check for Marker first because if it's a Marker it doesn't have a
+      // name attribute.
+      if (item == Marker) {
+        break;
+      } else if (item.tagName == name) {
+        return item;
+      }
+    }
+    return null;
+  }
+
+  void insertRoot(Token token) {
+    var element = createElement(token);
+    openElements.add(element);
+    document.nodes.add(element);
+  }
+
+  void insertDoctype(DoctypeToken token) {
+    var doctype = new DocumentType(token.name, token.publicId, token.systemId)
+        ..sourceSpan = token.span;
+    document.nodes.add(doctype);
+  }
+
+  void insertComment(StringToken token, [Node parent]) {
+    if (parent == null) {
+      parent = openElements.last;
+    }
+    parent.nodes.add(new Comment(token.data)..sourceSpan = token.span);
+  }
+
+  /** Create an element but don't insert it anywhere */
+  Element createElement(StartTagToken token) {
+    var name = token.name;
+    var namespace = token.namespace;
+    if (namespace == null) namespace = defaultNamespace;
+    var element = new Element(name, namespace)
+        ..attributes = token.data
+        ..sourceSpan = token.span;
+    return element;
+  }
+
+  Element insertElement(StartTagToken token) {
+    if (insertFromTable) return insertElementTable(token);
+    return insertElementNormal(token);
+  }
+
+  Element insertElementNormal(StartTagToken token) {
+    var name = token.name;
+    var namespace = token.namespace;
+    if (namespace == null) namespace = defaultNamespace;
+    var element = new Element(name, namespace)
+        ..attributes = token.data
+        ..sourceSpan = token.span;
+    openElements.last.nodes.add(element);
+    openElements.add(element);
+    return element;
+  }
+
+  Element insertElementTable(token) {
+    /** Create an element and insert it into the tree */
+    var element = createElement(token);
+    if (!tableInsertModeElements.contains(openElements.last.tagName)) {
+      return insertElementNormal(token);
+    } else {
+      // We should be in the InTable mode. This means we want to do
+      // special magic element rearranging
+      var nodePos = getTableMisnestedNodePosition();
+      if (nodePos[1] == null) {
+        // TODO(jmesserly): I don't think this is reachable. If insertFromTable
+        // is true, there will be a <table> element open, and it always has a
+        // parent pointer.
+        nodePos[0].nodes.add(element);
+      } else {
+        nodePos[0].insertBefore(element, nodePos[1]);
+      }
+      openElements.add(element);
+    }
+    return element;
+  }
+
+  /** Insert text data. */
+  void insertText(String data, FileSpan span) {
+    var parent = openElements.last;
+
+    if (!insertFromTable || insertFromTable &&
+        !tableInsertModeElements.contains(openElements.last.tagName)) {
+      _insertText(parent, data, span);
+    } else {
+      // We should be in the InTable mode. This means we want to do
+      // special magic element rearranging
+      var nodePos = getTableMisnestedNodePosition();
+      _insertText(nodePos[0], data, span, nodePos[1]);
+    }
+  }
+
+  /**
+   * Insert [data] as text in the current node, positioned before the
+   * start of node [refNode] or to the end of the node's text.
+   */
+  static void _insertText(Node parent, String data, FileSpan span,
+      [Element refNode]) {
+    var nodes = parent.nodes;
+    if (refNode == null) {
+      if (nodes.length > 0 && nodes.last is Text) {
+        Text last = nodes.last;
+        last.value = '${last.value}$data';
+
+        if (span != null) {
+          last.sourceSpan = span.file.span(last.sourceSpan.start.offset,
+              span.end.offset);
+        }
+      } else {
+        nodes.add(new Text(data)..sourceSpan = span);
+      }
+    } else {
+      int index = nodes.indexOf(refNode);
+      if (index > 0 && nodes[index - 1] is Text) {
+        Text last = nodes[index - 1];
+        last.value = '${last.value}$data';
+      } else {
+        nodes.insert(index, new Text(data)..sourceSpan = span);
+      }
+    }
+  }
+
+  /**
+   * Get the foster parent element, and sibling to insert before
+   * (or null) when inserting a misnested table node
+   */
+  List<Node> getTableMisnestedNodePosition() {
+    // The foster parent element is the one which comes before the most
+    // recently opened table element
+    // XXX - this is really inelegant
+    Node lastTable = null;
+    Node fosterParent = null;
+    var insertBefore = null;
+    for (Node elm in openElements.reversed) {
+      if (elm.tagName == "table") {
+        lastTable = elm;
+        break;
+      }
+    }
+    if (lastTable != null) {
+      // XXX - we should really check that this parent is actually a
+      // node here
+      if (lastTable.parent != null) {
+        fosterParent = lastTable.parent;
+        insertBefore = lastTable;
+      } else {
+        fosterParent = openElements[openElements.indexOf(lastTable) - 1];
+      }
+    } else {
+      fosterParent = openElements[0];
+    }
+    return [fosterParent, insertBefore];
+  }
+
+  void generateImpliedEndTags([String exclude]) {
+    var name = openElements.last.tagName;
+    // XXX td, th and tr are not actually needed
+    if (name != exclude && const ["dd", "dt", "li", "option", "optgroup", "p",
+        "rp", "rt"].contains(name)) {
+      openElements.removeLast();
+      // XXX This is not entirely what the specification says. We should
+      // investigate it more closely.
+      generateImpliedEndTags(exclude);
+    }
+  }
+
+  /** Return the final tree. */
+  Document getDocument() => document;
+
+  /** Return the final fragment. */
+  DocumentFragment getFragment() {
+    //XXX assert innerHTML
+    var fragment = new DocumentFragment();
+    openElements[0].reparentChildren(fragment);
+    return fragment;
+  }
+}
diff --git a/pkg/third_party/html5lib/lib/src/utils.dart b/pkg/third_party/html5lib/lib/src/utils.dart
new file mode 100644
index 0000000..ca81a41
--- /dev/null
+++ b/pkg/third_party/html5lib/lib/src/utils.dart
@@ -0,0 +1,124 @@
+/** Misc things that were useful when porting the code from Python. */
+library utils;
+
+import 'dart:collection';
+import 'constants.dart';
+
+typedef bool Predicate();
+
+class Pair<F, S> {
+  final F first;
+  final S second;
+
+  const Pair(this.first, this.second);
+
+  int get hashCode => 37 * first.hashCode + second.hashCode;
+  bool operator ==(other) => other.first == first && other.second == second;
+}
+
+int parseIntRadix(String str, [int radix = 10]) {
+  int val = 0;
+  for (int i = 0; i < str.length; i++) {
+    var digit = str.codeUnitAt(i);
+    if (digit >= LOWER_A) {
+      digit += 10 - LOWER_A;
+    } else if (digit >= UPPER_A) {
+      digit += 10 - UPPER_A;
+    } else {
+      digit -= ZERO;
+    }
+    val = val * radix + digit;
+  }
+  return val;
+}
+
+bool any(List<bool> iterable) => iterable.any((f) => f);
+
+bool startsWithAny(String str, List<String> prefixes) {
+  for (var prefix in prefixes) {
+    if (str.startsWith(prefix)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Like the python [:] operator.
+List slice(List list, int start, [int end]) {
+  if (end == null) end = list.length;
+  if (end < 0) end += list.length;
+
+  // Ensure the indexes are in bounds.
+  if (end < start) end = start;
+  if (end > list.length) end = list.length;
+  return list.sublist(start, end);
+}
+
+bool allWhitespace(String str) {
+  for (int i = 0; i < str.length; i++) {
+    if (!isWhitespaceCC(str.codeUnitAt(i))) return false;
+  }
+  return true;
+}
+
+String padWithZeros(String str, int size) {
+  if (str.length == size) return str;
+  var result = new StringBuffer();
+  size -= str.length;
+  for (int i = 0; i < size; i++) result.write('0');
+  result.write(str);
+  return result.toString();
+}
+
+// TODO(jmesserly): this implementation is pretty wrong, but I need something
+// quick until dartbug.com/1694 is fixed.
+/**
+ * Format a string like Python's % string format operator. Right now this only
+ * supports a [data] dictionary used with %s or %08x. Those were the only things
+ * needed for [errorMessages].
+ */
+String formatStr(String format, Map data) {
+  if (data == null) return format;
+  data.forEach((key, value) {
+    var result = new StringBuffer();
+    var search = '%($key)';
+    int last = 0, match;
+    while ((match = format.indexOf(search, last)) >= 0) {
+      result.write(format.substring(last, match));
+      match += search.length;
+
+      int digits = match;
+      while (isDigit(format[digits])) {
+        digits++;
+      }
+      int numberSize;
+      if (digits > match) {
+        numberSize = int.parse(format.substring(match, digits));
+        match = digits;
+      }
+
+      switch (format[match]) {
+        case 's':
+          result.write(value);
+          break;
+        case 'd':
+          var number = value.toString();
+          result.write(padWithZeros(number, numberSize));
+          break;
+        case 'x':
+          var number = value.toRadixString(16);
+          result.write(padWithZeros(number, numberSize));
+          break;
+        default: throw "not implemented: formatStr does not support format "
+            "character ${format[match]}";
+      }
+
+      last = match + 1;
+    }
+
+    result.write(format.substring(last, format.length));
+    format = result.toString();
+  });
+
+  return format;
+}
diff --git a/pkg/third_party/html5lib/pubspec.yaml b/pkg/third_party/html5lib/pubspec.yaml
new file mode 100644
index 0000000..79a09be
--- /dev/null
+++ b/pkg/third_party/html5lib/pubspec.yaml
@@ -0,0 +1,10 @@
+name: html5lib
+author: Dart Team <misc@dartlang.org>
+description: A library for working with HTML documents.
+homepage: https://github.com/dart-lang/html5lib
+dependencies:
+  source_maps: any
+dev_dependencies:
+  browser: any
+  path: any
+  unittest: any
diff --git a/pkg/third_party/html5lib/test/browser/browser_test.dart b/pkg/third_party/html5lib/test/browser/browser_test.dart
new file mode 100644
index 0000000..8339f48
--- /dev/null
+++ b/pkg/third_party/html5lib/test/browser/browser_test.dart
@@ -0,0 +1,14 @@
+library dom_compat_test;
+
+import 'dart:html';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/unittest.dart';
+
+part '../dom_compat_test_definitions.dart';
+
+main() {
+  groupSep = ' - ';
+  useHtmlConfiguration();
+
+  registerDomCompatTests();
+}
diff --git a/pkg/third_party/html5lib/test/browser/browser_test.html b/pkg/third_party/html5lib/test/browser/browser_test.html
new file mode 100644
index 0000000..bf8d297
--- /dev/null
+++ b/pkg/third_party/html5lib/test/browser/browser_test.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+  <head>
+    <title>Run the unit tests</title>
+  </head>
+  <body>
+    <script>
+      // Webkit is migrating from layoutTestController to testRunner, we use
+      // layoutTestController as a fallback until that settles in.
+      var runner = window.testRunner || window.layoutTestController;
+      if (runner) {
+        runner.dumpAsText();
+        runner.waitUntilDone();
+        window.addEventListener("message", receiveMessage, false);
+      }
+
+      function receiveMessage(e) {
+        console.log(e.data);
+        if (e.data == 'unittest-suite-done' && runner) {
+          runner.notifyDone();
+        }
+      }
+    </script>
+    <script type="application/dart" src="browser_test.dart"></script>
+    <script src="packages/browser/dart.js"></script>
+  </body>
+</html>
diff --git a/pkg/third_party/html5lib/test/data/parser_feature/raw_file.html b/pkg/third_party/html5lib/test/data/parser_feature/raw_file.html
new file mode 100644
index 0000000..bcdbf76
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/parser_feature/raw_file.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<html>
+<body>
+Hello world!
+</body>
+</html>
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/contentModelFlags.test b/pkg/third_party/html5lib/test/data/tokenizer/contentModelFlags.test
new file mode 100644
index 0000000..a8b1695
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/contentModelFlags.test
@@ -0,0 +1,75 @@
+{"tests": [
+
+{"description":"PLAINTEXT content model flag",
+"initialStates":["PLAINTEXT state"],
+"lastStartTag":"plaintext",
+"input":"<head>&body;",
+"output":[["Character", "<head>&body;"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp>",
+"output":[["Character", "foo"], ["EndTag", "xmp"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (case-insensitivity)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xMp>",
+"output":[["Character", "foo"], ["EndTag", "xmp"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (ending with space)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp ",
+"output":[["Character", "foo"], "ParseError"]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (ending with EOF)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp",
+"output":[["Character", "foo</xmp"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (ending with slash)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp/",
+"output":[["Character", "foo"], "ParseError"]},
+
+{"description":"End tag not closing RCDATA or RAWTEXT (ending with left-angle-bracket)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp<",
+"output":[["Character", "foo</xmp<"]]},
+
+{"description":"End tag with incorrect name in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"</foo>bar</xmp>",
+"output":[["Character", "</foo>bar"], ["EndTag", "xmp"]]},
+
+{"description":"End tag with incorrect name in RCDATA or RAWTEXT (starting like correct name)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"</foo>bar</xmpaar>",
+"output":[["Character", "</foo>bar</xmpaar>"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT, switching back to PCDATA",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp></baz>",
+"output":[["Character", "foo"], ["EndTag", "xmp"], ["EndTag", "baz"]]},
+
+{"description":"RAWTEXT w/ something looking like an entity",
+"initialStates":["RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"&foo;",
+"output":[["Character", "&foo;"]]},
+
+{"description":"RCDATA w/ an entity",
+"initialStates":["RCDATA state"],
+"lastStartTag":"textarea",
+"input":"&lt;",
+"output":[["Character", "<"]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/domjs.test b/pkg/third_party/html5lib/test/data/tokenizer/domjs.test
new file mode 100644
index 0000000..74771e2
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/domjs.test
@@ -0,0 +1,90 @@
+{
+    "tests": [
+        {
+            "description":"CR in bogus comment state",
+            "input":"<?\u000d",
+            "output":["ParseError", ["Comment", "?\u000a"]]
+        },
+        {
+            "description":"CRLF in bogus comment state",
+            "input":"<?\u000d\u000a",
+            "output":["ParseError", ["Comment", "?\u000a"]]
+        },
+        {
+            "description":"NUL in RCDATA and RAWTEXT",
+            "doubleEscaped":true,
+            "initialStates":["RCDATA state", "RAWTEXT state"],
+            "input":"\\u0000",
+            "output":["ParseError", ["Character", "\\uFFFD"]]
+        },
+        {
+            "description":"skip first BOM but not later ones",
+            "input":"\uFEFFfoo\uFEFFbar",
+            "output":[["Character", "foo\uFEFFbar"]]
+        },
+        {
+            "description":"Non BMP-charref in in RCDATA",
+            "initialStates":["RCDATA state"],
+            "input":"&NotEqualTilde;",
+            "output":[["Character", "\u2242\u0338"]]
+        },
+        {
+            "description":"Bad charref in in RCDATA",
+            "initialStates":["RCDATA state"],
+            "input":"&NotEqualTild;",
+            "output":["ParseError", ["Character", "&NotEqualTild;"]]
+        },
+        {
+            "description":"lowercase endtags in RCDATA and RAWTEXT",
+            "initialStates":["RCDATA state", "RAWTEXT state"],
+            "lastStartTag":"xmp",
+            "input":"</XMP>",
+            "output":[["EndTag","xmp"]]
+        },
+        {
+            "description":"bad endtag in RCDATA and RAWTEXT",
+            "initialStates":["RCDATA state", "RAWTEXT state"],
+            "lastStartTag":"xmp",
+            "input":"</ XMP>",
+            "output":[["Character","</ XMP>"]]
+        },
+        {
+            "description":"bad endtag in RCDATA and RAWTEXT",
+            "initialStates":["RCDATA state", "RAWTEXT state"],
+            "lastStartTag":"xmp",
+            "input":"</xm>",
+            "output":[["Character","</xm>"]]
+        },
+        {
+            "description":"bad endtag in RCDATA and RAWTEXT",
+            "initialStates":["RCDATA state", "RAWTEXT state"],
+            "lastStartTag":"xmp",
+            "input":"</xm ",
+            "output":[["Character","</xm "]]
+        },
+        {
+            "description":"bad endtag in RCDATA and RAWTEXT",
+            "initialStates":["RCDATA state", "RAWTEXT state"],
+            "lastStartTag":"xmp",
+            "input":"</xm/",
+            "output":[["Character","</xm/"]]
+        },
+        {
+            "description":"Non BMP-charref in attribute",
+            "input":"<p id=\"&NotEqualTilde;\">",
+            "output":[["StartTag", "p", {"id":"\u2242\u0338"}]]
+        },
+        {
+            "description":"--!NUL in comment ",
+            "doubleEscaped":true,
+            "input":"<!----!\\u0000-->",
+            "output":["ParseError", ["Comment", "--!\\uFFFD"]]
+        },
+        {
+            "description":"space EOF after doctype ",
+            "input":"<!DOCTYPE html ",
+            "output":["ParseError", ["DOCTYPE", "html", null, null , false]]
+        }
+
+    ]
+}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/entities.test b/pkg/third_party/html5lib/test/data/tokenizer/entities.test
new file mode 100644
index 0000000..1cb17a7
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/entities.test
@@ -0,0 +1,283 @@
+{"tests": [
+
+{"description": "Undefined named entity in attribute value ending in semicolon and whose name starts with a known entity name.",
+"input":"<h a='&noti;'>",
+"output": ["ParseError", ["StartTag", "h", {"a": "&noti;"}]]},
+
+{"description": "Entity name followed by the equals sign in an attribute value.",
+"input":"<h a='&lang='>",
+"output": ["ParseError", ["StartTag", "h", {"a": "&lang="}]]},
+
+{"description": "CR as numeric entity",
+"input":"&#013;",
+"output": ["ParseError", ["Character", "\r"]]},
+
+{"description": "CR as hexadecimal numeric entity",
+"input":"&#x00D;",
+"output": ["ParseError", ["Character", "\r"]]},
+
+{"description": "Windows-1252 EURO SIGN numeric entity.",
+"input":"&#0128;",
+"output": ["ParseError", ["Character", "\u20AC"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"&#0129;",
+"output": ["ParseError", ["Character", "\u0081"]]},
+
+{"description": "Windows-1252 SINGLE LOW-9 QUOTATION MARK numeric entity.",
+"input":"&#0130;",
+"output": ["ParseError", ["Character", "\u201A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER F WITH HOOK numeric entity.",
+"input":"&#0131;",
+"output": ["ParseError", ["Character", "\u0192"]]},
+
+{"description": "Windows-1252 DOUBLE LOW-9 QUOTATION MARK numeric entity.",
+"input":"&#0132;",
+"output": ["ParseError", ["Character", "\u201E"]]},
+
+{"description": "Windows-1252 HORIZONTAL ELLIPSIS numeric entity.",
+"input":"&#0133;",
+"output": ["ParseError", ["Character", "\u2026"]]},
+
+{"description": "Windows-1252 DAGGER numeric entity.",
+"input":"&#0134;",
+"output": ["ParseError", ["Character", "\u2020"]]},
+
+{"description": "Windows-1252 DOUBLE DAGGER numeric entity.",
+"input":"&#0135;",
+"output": ["ParseError", ["Character", "\u2021"]]},
+
+{"description": "Windows-1252 MODIFIER LETTER CIRCUMFLEX ACCENT numeric entity.",
+"input":"&#0136;",
+"output": ["ParseError", ["Character", "\u02C6"]]},
+
+{"description": "Windows-1252 PER MILLE SIGN numeric entity.",
+"input":"&#0137;",
+"output": ["ParseError", ["Character", "\u2030"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER S WITH CARON numeric entity.",
+"input":"&#0138;",
+"output": ["ParseError", ["Character", "\u0160"]]},
+
+{"description": "Windows-1252 SINGLE LEFT-POINTING ANGLE QUOTATION MARK numeric entity.",
+"input":"&#0139;",
+"output": ["ParseError", ["Character", "\u2039"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LIGATURE OE numeric entity.",
+"input":"&#0140;",
+"output": ["ParseError", ["Character", "\u0152"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"&#0141;",
+"output": ["ParseError", ["Character", "\u008D"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER Z WITH CARON numeric entity.",
+"input":"&#0142;",
+"output": ["ParseError", ["Character", "\u017D"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"&#0143;",
+"output": ["ParseError", ["Character", "\u008F"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"&#0144;",
+"output": ["ParseError", ["Character", "\u0090"]]},
+
+{"description": "Windows-1252 LEFT SINGLE QUOTATION MARK numeric entity.",
+"input":"&#0145;",
+"output": ["ParseError", ["Character", "\u2018"]]},
+
+{"description": "Windows-1252 RIGHT SINGLE QUOTATION MARK numeric entity.",
+"input":"&#0146;",
+"output": ["ParseError", ["Character", "\u2019"]]},
+
+{"description": "Windows-1252 LEFT DOUBLE QUOTATION MARK numeric entity.",
+"input":"&#0147;",
+"output": ["ParseError", ["Character", "\u201C"]]},
+
+{"description": "Windows-1252 RIGHT DOUBLE QUOTATION MARK numeric entity.",
+"input":"&#0148;",
+"output": ["ParseError", ["Character", "\u201D"]]},
+
+{"description": "Windows-1252 BULLET numeric entity.",
+"input":"&#0149;",
+"output": ["ParseError", ["Character", "\u2022"]]},
+
+{"description": "Windows-1252 EN DASH numeric entity.",
+"input":"&#0150;",
+"output": ["ParseError", ["Character", "\u2013"]]},
+
+{"description": "Windows-1252 EM DASH numeric entity.",
+"input":"&#0151;",
+"output": ["ParseError", ["Character", "\u2014"]]},
+
+{"description": "Windows-1252 SMALL TILDE numeric entity.",
+"input":"&#0152;",
+"output": ["ParseError", ["Character", "\u02DC"]]},
+
+{"description": "Windows-1252 TRADE MARK SIGN numeric entity.",
+"input":"&#0153;",
+"output": ["ParseError", ["Character", "\u2122"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER S WITH CARON numeric entity.",
+"input":"&#0154;",
+"output": ["ParseError", ["Character", "\u0161"]]},
+
+{"description": "Windows-1252 SINGLE RIGHT-POINTING ANGLE QUOTATION MARK numeric entity.",
+"input":"&#0155;",
+"output": ["ParseError", ["Character", "\u203A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LIGATURE OE numeric entity.",
+"input":"&#0156;",
+"output": ["ParseError", ["Character", "\u0153"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"&#0157;",
+"output": ["ParseError", ["Character", "\u009D"]]},
+
+{"description": "Windows-1252 EURO SIGN hexadecimal numeric entity.",
+"input":"&#x080;",
+"output": ["ParseError", ["Character", "\u20AC"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"&#x081;",
+"output": ["ParseError", ["Character", "\u0081"]]},
+
+{"description": "Windows-1252 SINGLE LOW-9 QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x082;",
+"output": ["ParseError", ["Character", "\u201A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER F WITH HOOK hexadecimal numeric entity.",
+"input":"&#x083;",
+"output": ["ParseError", ["Character", "\u0192"]]},
+
+{"description": "Windows-1252 DOUBLE LOW-9 QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x084;",
+"output": ["ParseError", ["Character", "\u201E"]]},
+
+{"description": "Windows-1252 HORIZONTAL ELLIPSIS hexadecimal numeric entity.",
+"input":"&#x085;",
+"output": ["ParseError", ["Character", "\u2026"]]},
+
+{"description": "Windows-1252 DAGGER hexadecimal numeric entity.",
+"input":"&#x086;",
+"output": ["ParseError", ["Character", "\u2020"]]},
+
+{"description": "Windows-1252 DOUBLE DAGGER hexadecimal numeric entity.",
+"input":"&#x087;",
+"output": ["ParseError", ["Character", "\u2021"]]},
+
+{"description": "Windows-1252 MODIFIER LETTER CIRCUMFLEX ACCENT hexadecimal numeric entity.",
+"input":"&#x088;",
+"output": ["ParseError", ["Character", "\u02C6"]]},
+
+{"description": "Windows-1252 PER MILLE SIGN hexadecimal numeric entity.",
+"input":"&#x089;",
+"output": ["ParseError", ["Character", "\u2030"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER S WITH CARON hexadecimal numeric entity.",
+"input":"&#x08A;",
+"output": ["ParseError", ["Character", "\u0160"]]},
+
+{"description": "Windows-1252 SINGLE LEFT-POINTING ANGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x08B;",
+"output": ["ParseError", ["Character", "\u2039"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LIGATURE OE hexadecimal numeric entity.",
+"input":"&#x08C;",
+"output": ["ParseError", ["Character", "\u0152"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"&#x08D;",
+"output": ["ParseError", ["Character", "\u008D"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER Z WITH CARON hexadecimal numeric entity.",
+"input":"&#x08E;",
+"output": ["ParseError", ["Character", "\u017D"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"&#x08F;",
+"output": ["ParseError", ["Character", "\u008F"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"&#x090;",
+"output": ["ParseError", ["Character", "\u0090"]]},
+
+{"description": "Windows-1252 LEFT SINGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x091;",
+"output": ["ParseError", ["Character", "\u2018"]]},
+
+{"description": "Windows-1252 RIGHT SINGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x092;",
+"output": ["ParseError", ["Character", "\u2019"]]},
+
+{"description": "Windows-1252 LEFT DOUBLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x093;",
+"output": ["ParseError", ["Character", "\u201C"]]},
+
+{"description": "Windows-1252 RIGHT DOUBLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x094;",
+"output": ["ParseError", ["Character", "\u201D"]]},
+
+{"description": "Windows-1252 BULLET hexadecimal numeric entity.",
+"input":"&#x095;",
+"output": ["ParseError", ["Character", "\u2022"]]},
+
+{"description": "Windows-1252 EN DASH hexadecimal numeric entity.",
+"input":"&#x096;",
+"output": ["ParseError", ["Character", "\u2013"]]},
+
+{"description": "Windows-1252 EM DASH hexadecimal numeric entity.",
+"input":"&#x097;",
+"output": ["ParseError", ["Character", "\u2014"]]},
+
+{"description": "Windows-1252 SMALL TILDE hexadecimal numeric entity.",
+"input":"&#x098;",
+"output": ["ParseError", ["Character", "\u02DC"]]},
+
+{"description": "Windows-1252 TRADE MARK SIGN hexadecimal numeric entity.",
+"input":"&#x099;",
+"output": ["ParseError", ["Character", "\u2122"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER S WITH CARON hexadecimal numeric entity.",
+"input":"&#x09A;",
+"output": ["ParseError", ["Character", "\u0161"]]},
+
+{"description": "Windows-1252 SINGLE RIGHT-POINTING ANGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"&#x09B;",
+"output": ["ParseError", ["Character", "\u203A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LIGATURE OE hexadecimal numeric entity.",
+"input":"&#x09C;",
+"output": ["ParseError", ["Character", "\u0153"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"&#x09D;",
+"output": ["ParseError", ["Character", "\u009D"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER Z WITH CARON hexadecimal numeric entity.",
+"input":"&#x09E;",
+"output": ["ParseError", ["Character", "\u017E"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER Y WITH DIAERESIS hexadecimal numeric entity.",
+"input":"&#x09F;",
+"output": ["ParseError", ["Character", "\u0178"]]},
+
+{"description": "Decimal numeric entity followed by hex character a.",
+"input":"&#97a",
+"output": ["ParseError", ["Character", "aa"]]},
+
+{"description": "Decimal numeric entity followed by hex character A.",
+"input":"&#97A",
+"output": ["ParseError", ["Character", "aA"]]},
+
+{"description": "Decimal numeric entity followed by hex character f.",
+"input":"&#97f",
+"output": ["ParseError", ["Character", "af"]]},
+
+{"description": "Decimal numeric entity followed by hex character A.",
+"input":"&#97F",
+"output": ["ParseError", ["Character", "aF"]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/escapeFlag.test b/pkg/third_party/html5lib/test/data/tokenizer/escapeFlag.test
new file mode 100644
index 0000000..18cb430
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/escapeFlag.test
@@ -0,0 +1,33 @@
+{"tests": [
+
+{"description":"Commented close tag in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!--</xmp>--></xmp>",
+"output":[["Character", "foo<!--"], ["EndTag", "xmp"], ["Character", "-->"], ["EndTag", "xmp"]]},
+
+{"description":"Bogus comment in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!-->baz</xmp>",
+"output":[["Character", "foo<!-->baz"], ["EndTag", "xmp"]]},
+
+{"description":"End tag surrounded by bogus comment in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!--></xmp><!-->baz</xmp>",
+"output":[["Character", "foo<!-->"], ["EndTag", "xmp"], "ParseError", ["Comment", ""], ["Character", "baz"], ["EndTag", "xmp"]]},
+
+{"description":"Commented entities in RCDATA",
+"initialStates":["RCDATA state"],
+"lastStartTag":"xmp",
+"input":" &amp; <!-- &amp; --> &amp; </xmp>",
+"output":[["Character", " & <!-- & --> & "], ["EndTag", "xmp"]]},
+
+{"description":"Incorrect comment ending sequences in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!-- x --x>x-- >x--!>x--<></xmp>",
+"output":[["Character", "foo<!-- x --x>x-- >x--!>x--<>"], ["EndTag", "xmp"]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/namedEntities.test b/pkg/third_party/html5lib/test/data/tokenizer/namedEntities.test
new file mode 100644
index 0000000..4a51c9c
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/namedEntities.test
@@ -0,0 +1,44189 @@
+{
+    "tests": [
+        {
+            "input": "&AElig", 
+            "description": "Named entity: AElig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&AElig;", 
+            "description": "Named entity: AElig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&AMP", 
+            "description": "Named entity: AMP without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&"
+                ]
+            ]
+        }, 
+        {
+            "input": "&AMP;", 
+            "description": "Named entity: AMP; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "&"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aacute", 
+            "description": "Named entity: Aacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aacute;", 
+            "description": "Named entity: Aacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Abreve", 
+            "description": "Bad named entity: Abreve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Abreve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Abreve;", 
+            "description": "Named entity: Abreve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0102"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Acirc", 
+            "description": "Named entity: Acirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Acirc;", 
+            "description": "Named entity: Acirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Acy", 
+            "description": "Bad named entity: Acy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Acy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Acy;", 
+            "description": "Named entity: Acy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0410"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Afr", 
+            "description": "Bad named entity: Afr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Afr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Afr;", 
+            "description": "Named entity: Afr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd04"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Agrave", 
+            "description": "Named entity: Agrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Agrave;", 
+            "description": "Named entity: Agrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Alpha", 
+            "description": "Bad named entity: Alpha without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Alpha"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Alpha;", 
+            "description": "Named entity: Alpha; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0391"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Amacr", 
+            "description": "Bad named entity: Amacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Amacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Amacr;", 
+            "description": "Named entity: Amacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0100"
+                ]
+            ]
+        }, 
+        {
+            "input": "&And", 
+            "description": "Bad named entity: And without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&And"
+                ]
+            ]
+        }, 
+        {
+            "input": "&And;", 
+            "description": "Named entity: And; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a53"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aogon", 
+            "description": "Bad named entity: Aogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Aogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aogon;", 
+            "description": "Named entity: Aogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0104"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aopf", 
+            "description": "Bad named entity: Aopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Aopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aopf;", 
+            "description": "Named entity: Aopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd38"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ApplyFunction", 
+            "description": "Bad named entity: ApplyFunction without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ApplyFunction"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ApplyFunction;", 
+            "description": "Named entity: ApplyFunction; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2061"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aring", 
+            "description": "Named entity: Aring without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Aring;", 
+            "description": "Named entity: Aring; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ascr", 
+            "description": "Bad named entity: Ascr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ascr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ascr;", 
+            "description": "Named entity: Ascr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udc9c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Assign", 
+            "description": "Bad named entity: Assign without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Assign"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Assign;", 
+            "description": "Named entity: Assign; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2254"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Atilde", 
+            "description": "Named entity: Atilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Atilde;", 
+            "description": "Named entity: Atilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Auml", 
+            "description": "Named entity: Auml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Auml;", 
+            "description": "Named entity: Auml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Backslash", 
+            "description": "Bad named entity: Backslash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Backslash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Backslash;", 
+            "description": "Named entity: Backslash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2216"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Barv", 
+            "description": "Bad named entity: Barv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Barv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Barv;", 
+            "description": "Named entity: Barv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ae7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Barwed", 
+            "description": "Bad named entity: Barwed without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Barwed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Barwed;", 
+            "description": "Named entity: Barwed; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2306"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bcy", 
+            "description": "Bad named entity: Bcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Bcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bcy;", 
+            "description": "Named entity: Bcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0411"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Because", 
+            "description": "Bad named entity: Because without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Because"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Because;", 
+            "description": "Named entity: Because; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2235"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bernoullis", 
+            "description": "Bad named entity: Bernoullis without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Bernoullis"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bernoullis;", 
+            "description": "Named entity: Bernoullis; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u212c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Beta", 
+            "description": "Bad named entity: Beta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Beta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Beta;", 
+            "description": "Named entity: Beta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0392"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bfr", 
+            "description": "Bad named entity: Bfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Bfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bfr;", 
+            "description": "Named entity: Bfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd05"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bopf", 
+            "description": "Bad named entity: Bopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Bopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bopf;", 
+            "description": "Named entity: Bopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd39"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Breve", 
+            "description": "Bad named entity: Breve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Breve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Breve;", 
+            "description": "Named entity: Breve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02d8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bscr", 
+            "description": "Bad named entity: Bscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Bscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bscr;", 
+            "description": "Named entity: Bscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u212c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bumpeq", 
+            "description": "Bad named entity: Bumpeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Bumpeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Bumpeq;", 
+            "description": "Named entity: Bumpeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CHcy", 
+            "description": "Bad named entity: CHcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CHcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CHcy;", 
+            "description": "Named entity: CHcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0427"
+                ]
+            ]
+        }, 
+        {
+            "input": "&COPY", 
+            "description": "Named entity: COPY without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&COPY;", 
+            "description": "Named entity: COPY; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cacute", 
+            "description": "Bad named entity: Cacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cacute;", 
+            "description": "Named entity: Cacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0106"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cap", 
+            "description": "Bad named entity: Cap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cap;", 
+            "description": "Named entity: Cap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CapitalDifferentialD", 
+            "description": "Bad named entity: CapitalDifferentialD without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CapitalDifferentialD"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CapitalDifferentialD;", 
+            "description": "Named entity: CapitalDifferentialD; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2145"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cayleys", 
+            "description": "Bad named entity: Cayleys without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cayleys"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cayleys;", 
+            "description": "Named entity: Cayleys; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u212d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ccaron", 
+            "description": "Bad named entity: Ccaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ccaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ccaron;", 
+            "description": "Named entity: Ccaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u010c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ccedil", 
+            "description": "Named entity: Ccedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ccedil;", 
+            "description": "Named entity: Ccedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ccirc", 
+            "description": "Bad named entity: Ccirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ccirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ccirc;", 
+            "description": "Named entity: Ccirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0108"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cconint", 
+            "description": "Bad named entity: Cconint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cconint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cconint;", 
+            "description": "Named entity: Cconint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2230"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cdot", 
+            "description": "Bad named entity: Cdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cdot;", 
+            "description": "Named entity: Cdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u010a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cedilla", 
+            "description": "Bad named entity: Cedilla without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cedilla"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cedilla;", 
+            "description": "Named entity: Cedilla; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CenterDot", 
+            "description": "Bad named entity: CenterDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CenterDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CenterDot;", 
+            "description": "Named entity: CenterDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cfr", 
+            "description": "Bad named entity: Cfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cfr;", 
+            "description": "Named entity: Cfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u212d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Chi", 
+            "description": "Bad named entity: Chi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Chi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Chi;", 
+            "description": "Named entity: Chi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CircleDot", 
+            "description": "Bad named entity: CircleDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CircleDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CircleDot;", 
+            "description": "Named entity: CircleDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2299"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CircleMinus", 
+            "description": "Bad named entity: CircleMinus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CircleMinus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CircleMinus;", 
+            "description": "Named entity: CircleMinus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2296"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CirclePlus", 
+            "description": "Bad named entity: CirclePlus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CirclePlus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CirclePlus;", 
+            "description": "Named entity: CirclePlus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2295"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CircleTimes", 
+            "description": "Bad named entity: CircleTimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CircleTimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CircleTimes;", 
+            "description": "Named entity: CircleTimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2297"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ClockwiseContourIntegral", 
+            "description": "Bad named entity: ClockwiseContourIntegral without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ClockwiseContourIntegral"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ClockwiseContourIntegral;", 
+            "description": "Named entity: ClockwiseContourIntegral; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2232"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CloseCurlyDoubleQuote", 
+            "description": "Bad named entity: CloseCurlyDoubleQuote without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CloseCurlyDoubleQuote"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CloseCurlyDoubleQuote;", 
+            "description": "Named entity: CloseCurlyDoubleQuote; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CloseCurlyQuote", 
+            "description": "Bad named entity: CloseCurlyQuote without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CloseCurlyQuote"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CloseCurlyQuote;", 
+            "description": "Named entity: CloseCurlyQuote; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2019"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Colon", 
+            "description": "Bad named entity: Colon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Colon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Colon;", 
+            "description": "Named entity: Colon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2237"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Colone", 
+            "description": "Bad named entity: Colone without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Colone"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Colone;", 
+            "description": "Named entity: Colone; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a74"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Congruent", 
+            "description": "Bad named entity: Congruent without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Congruent"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Congruent;", 
+            "description": "Named entity: Congruent; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2261"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Conint", 
+            "description": "Bad named entity: Conint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Conint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Conint;", 
+            "description": "Named entity: Conint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ContourIntegral", 
+            "description": "Bad named entity: ContourIntegral without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ContourIntegral"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ContourIntegral;", 
+            "description": "Named entity: ContourIntegral; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Copf", 
+            "description": "Bad named entity: Copf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Copf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Copf;", 
+            "description": "Named entity: Copf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2102"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Coproduct", 
+            "description": "Bad named entity: Coproduct without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Coproduct"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Coproduct;", 
+            "description": "Named entity: Coproduct; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2210"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CounterClockwiseContourIntegral", 
+            "description": "Bad named entity: CounterClockwiseContourIntegral without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CounterClockwiseContourIntegral"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CounterClockwiseContourIntegral;", 
+            "description": "Named entity: CounterClockwiseContourIntegral; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2233"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cross", 
+            "description": "Bad named entity: Cross without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cross"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cross;", 
+            "description": "Named entity: Cross; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a2f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cscr", 
+            "description": "Bad named entity: Cscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cscr;", 
+            "description": "Named entity: Cscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udc9e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cup", 
+            "description": "Bad named entity: Cup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Cup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Cup;", 
+            "description": "Named entity: Cup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CupCap", 
+            "description": "Bad named entity: CupCap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&CupCap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&CupCap;", 
+            "description": "Named entity: CupCap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DD", 
+            "description": "Bad named entity: DD without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DD"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DD;", 
+            "description": "Named entity: DD; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2145"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DDotrahd", 
+            "description": "Bad named entity: DDotrahd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DDotrahd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DDotrahd;", 
+            "description": "Named entity: DDotrahd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2911"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DJcy", 
+            "description": "Bad named entity: DJcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DJcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DJcy;", 
+            "description": "Named entity: DJcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0402"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DScy", 
+            "description": "Bad named entity: DScy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DScy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DScy;", 
+            "description": "Named entity: DScy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0405"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DZcy", 
+            "description": "Bad named entity: DZcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DZcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DZcy;", 
+            "description": "Named entity: DZcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u040f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dagger", 
+            "description": "Bad named entity: Dagger without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dagger"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dagger;", 
+            "description": "Named entity: Dagger; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2021"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Darr", 
+            "description": "Bad named entity: Darr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Darr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Darr;", 
+            "description": "Named entity: Darr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dashv", 
+            "description": "Bad named entity: Dashv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dashv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dashv;", 
+            "description": "Named entity: Dashv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ae4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dcaron", 
+            "description": "Bad named entity: Dcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dcaron;", 
+            "description": "Named entity: Dcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u010e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dcy", 
+            "description": "Bad named entity: Dcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dcy;", 
+            "description": "Named entity: Dcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0414"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Del", 
+            "description": "Bad named entity: Del without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Del"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Del;", 
+            "description": "Named entity: Del; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2207"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Delta", 
+            "description": "Bad named entity: Delta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Delta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Delta;", 
+            "description": "Named entity: Delta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0394"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dfr", 
+            "description": "Bad named entity: Dfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dfr;", 
+            "description": "Named entity: Dfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd07"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalAcute", 
+            "description": "Bad named entity: DiacriticalAcute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DiacriticalAcute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalAcute;", 
+            "description": "Named entity: DiacriticalAcute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalDot", 
+            "description": "Bad named entity: DiacriticalDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DiacriticalDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalDot;", 
+            "description": "Named entity: DiacriticalDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02d9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalDoubleAcute", 
+            "description": "Bad named entity: DiacriticalDoubleAcute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DiacriticalDoubleAcute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalDoubleAcute;", 
+            "description": "Named entity: DiacriticalDoubleAcute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalGrave", 
+            "description": "Bad named entity: DiacriticalGrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DiacriticalGrave"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalGrave;", 
+            "description": "Named entity: DiacriticalGrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "`"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalTilde", 
+            "description": "Bad named entity: DiacriticalTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DiacriticalTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DiacriticalTilde;", 
+            "description": "Named entity: DiacriticalTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Diamond", 
+            "description": "Bad named entity: Diamond without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Diamond"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Diamond;", 
+            "description": "Named entity: Diamond; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DifferentialD", 
+            "description": "Bad named entity: DifferentialD without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DifferentialD"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DifferentialD;", 
+            "description": "Named entity: DifferentialD; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2146"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dopf", 
+            "description": "Bad named entity: Dopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dopf;", 
+            "description": "Named entity: Dopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd3b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dot", 
+            "description": "Bad named entity: Dot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dot;", 
+            "description": "Named entity: Dot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DotDot", 
+            "description": "Bad named entity: DotDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DotDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DotDot;", 
+            "description": "Named entity: DotDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u20dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DotEqual", 
+            "description": "Bad named entity: DotEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DotEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DotEqual;", 
+            "description": "Named entity: DotEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2250"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleContourIntegral", 
+            "description": "Bad named entity: DoubleContourIntegral without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleContourIntegral"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleContourIntegral;", 
+            "description": "Named entity: DoubleContourIntegral; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleDot", 
+            "description": "Bad named entity: DoubleDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleDot;", 
+            "description": "Named entity: DoubleDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleDownArrow", 
+            "description": "Bad named entity: DoubleDownArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleDownArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleDownArrow;", 
+            "description": "Named entity: DoubleDownArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLeftArrow", 
+            "description": "Bad named entity: DoubleLeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleLeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLeftArrow;", 
+            "description": "Named entity: DoubleLeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLeftRightArrow", 
+            "description": "Bad named entity: DoubleLeftRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleLeftRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLeftRightArrow;", 
+            "description": "Named entity: DoubleLeftRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLeftTee", 
+            "description": "Bad named entity: DoubleLeftTee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleLeftTee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLeftTee;", 
+            "description": "Named entity: DoubleLeftTee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ae4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLongLeftArrow", 
+            "description": "Bad named entity: DoubleLongLeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleLongLeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLongLeftArrow;", 
+            "description": "Named entity: DoubleLongLeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLongLeftRightArrow", 
+            "description": "Bad named entity: DoubleLongLeftRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleLongLeftRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLongLeftRightArrow;", 
+            "description": "Named entity: DoubleLongLeftRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27fa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLongRightArrow", 
+            "description": "Bad named entity: DoubleLongRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleLongRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleLongRightArrow;", 
+            "description": "Named entity: DoubleLongRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleRightArrow", 
+            "description": "Bad named entity: DoubleRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleRightArrow;", 
+            "description": "Named entity: DoubleRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleRightTee", 
+            "description": "Bad named entity: DoubleRightTee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleRightTee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleRightTee;", 
+            "description": "Named entity: DoubleRightTee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleUpArrow", 
+            "description": "Bad named entity: DoubleUpArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleUpArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleUpArrow;", 
+            "description": "Named entity: DoubleUpArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleUpDownArrow", 
+            "description": "Bad named entity: DoubleUpDownArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleUpDownArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleUpDownArrow;", 
+            "description": "Named entity: DoubleUpDownArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleVerticalBar", 
+            "description": "Bad named entity: DoubleVerticalBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DoubleVerticalBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DoubleVerticalBar;", 
+            "description": "Named entity: DoubleVerticalBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2225"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownArrow", 
+            "description": "Bad named entity: DownArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownArrow;", 
+            "description": "Named entity: DownArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2193"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownArrowBar", 
+            "description": "Bad named entity: DownArrowBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownArrowBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownArrowBar;", 
+            "description": "Named entity: DownArrowBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2913"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownArrowUpArrow", 
+            "description": "Bad named entity: DownArrowUpArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownArrowUpArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownArrowUpArrow;", 
+            "description": "Named entity: DownArrowUpArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownBreve", 
+            "description": "Bad named entity: DownBreve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownBreve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownBreve;", 
+            "description": "Named entity: DownBreve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0311"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftRightVector", 
+            "description": "Bad named entity: DownLeftRightVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownLeftRightVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftRightVector;", 
+            "description": "Named entity: DownLeftRightVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2950"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftTeeVector", 
+            "description": "Bad named entity: DownLeftTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownLeftTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftTeeVector;", 
+            "description": "Named entity: DownLeftTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u295e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftVector", 
+            "description": "Bad named entity: DownLeftVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownLeftVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftVector;", 
+            "description": "Named entity: DownLeftVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftVectorBar", 
+            "description": "Bad named entity: DownLeftVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownLeftVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownLeftVectorBar;", 
+            "description": "Named entity: DownLeftVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2956"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownRightTeeVector", 
+            "description": "Bad named entity: DownRightTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownRightTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownRightTeeVector;", 
+            "description": "Named entity: DownRightTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u295f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownRightVector", 
+            "description": "Bad named entity: DownRightVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownRightVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownRightVector;", 
+            "description": "Named entity: DownRightVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownRightVectorBar", 
+            "description": "Bad named entity: DownRightVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownRightVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownRightVectorBar;", 
+            "description": "Named entity: DownRightVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2957"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownTee", 
+            "description": "Bad named entity: DownTee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownTee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownTee;", 
+            "description": "Named entity: DownTee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownTeeArrow", 
+            "description": "Bad named entity: DownTeeArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&DownTeeArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&DownTeeArrow;", 
+            "description": "Named entity: DownTeeArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Downarrow", 
+            "description": "Bad named entity: Downarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Downarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Downarrow;", 
+            "description": "Named entity: Downarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dscr", 
+            "description": "Bad named entity: Dscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dscr;", 
+            "description": "Named entity: Dscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udc9f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dstrok", 
+            "description": "Bad named entity: Dstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Dstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Dstrok;", 
+            "description": "Named entity: Dstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0110"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ENG", 
+            "description": "Bad named entity: ENG without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ENG"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ENG;", 
+            "description": "Named entity: ENG; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u014a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ETH", 
+            "description": "Named entity: ETH without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ETH;", 
+            "description": "Named entity: ETH; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eacute", 
+            "description": "Named entity: Eacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eacute;", 
+            "description": "Named entity: Eacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ecaron", 
+            "description": "Bad named entity: Ecaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ecaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ecaron;", 
+            "description": "Named entity: Ecaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u011a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ecirc", 
+            "description": "Named entity: Ecirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ecirc;", 
+            "description": "Named entity: Ecirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ecy", 
+            "description": "Bad named entity: Ecy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ecy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ecy;", 
+            "description": "Named entity: Ecy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u042d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Edot", 
+            "description": "Bad named entity: Edot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Edot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Edot;", 
+            "description": "Named entity: Edot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0116"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Efr", 
+            "description": "Bad named entity: Efr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Efr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Efr;", 
+            "description": "Named entity: Efr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd08"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Egrave", 
+            "description": "Named entity: Egrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Egrave;", 
+            "description": "Named entity: Egrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Element", 
+            "description": "Bad named entity: Element without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Element"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Element;", 
+            "description": "Named entity: Element; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2208"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Emacr", 
+            "description": "Bad named entity: Emacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Emacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Emacr;", 
+            "description": "Named entity: Emacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0112"
+                ]
+            ]
+        }, 
+        {
+            "input": "&EmptySmallSquare", 
+            "description": "Bad named entity: EmptySmallSquare without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&EmptySmallSquare"
+                ]
+            ]
+        }, 
+        {
+            "input": "&EmptySmallSquare;", 
+            "description": "Named entity: EmptySmallSquare; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25fb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&EmptyVerySmallSquare", 
+            "description": "Bad named entity: EmptyVerySmallSquare without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&EmptyVerySmallSquare"
+                ]
+            ]
+        }, 
+        {
+            "input": "&EmptyVerySmallSquare;", 
+            "description": "Named entity: EmptyVerySmallSquare; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eogon", 
+            "description": "Bad named entity: Eogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Eogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eogon;", 
+            "description": "Named entity: Eogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0118"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eopf", 
+            "description": "Bad named entity: Eopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Eopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eopf;", 
+            "description": "Named entity: Eopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd3c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Epsilon", 
+            "description": "Bad named entity: Epsilon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Epsilon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Epsilon;", 
+            "description": "Named entity: Epsilon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0395"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Equal", 
+            "description": "Bad named entity: Equal without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Equal"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Equal;", 
+            "description": "Named entity: Equal; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a75"
+                ]
+            ]
+        }, 
+        {
+            "input": "&EqualTilde", 
+            "description": "Bad named entity: EqualTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&EqualTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&EqualTilde;", 
+            "description": "Named entity: EqualTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2242"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Equilibrium", 
+            "description": "Bad named entity: Equilibrium without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Equilibrium"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Equilibrium;", 
+            "description": "Named entity: Equilibrium; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Escr", 
+            "description": "Bad named entity: Escr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Escr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Escr;", 
+            "description": "Named entity: Escr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2130"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Esim", 
+            "description": "Bad named entity: Esim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Esim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Esim;", 
+            "description": "Named entity: Esim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a73"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eta", 
+            "description": "Bad named entity: Eta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Eta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Eta;", 
+            "description": "Named entity: Eta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0397"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Euml", 
+            "description": "Named entity: Euml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Euml;", 
+            "description": "Named entity: Euml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Exists", 
+            "description": "Bad named entity: Exists without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Exists"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Exists;", 
+            "description": "Named entity: Exists; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2203"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ExponentialE", 
+            "description": "Bad named entity: ExponentialE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ExponentialE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ExponentialE;", 
+            "description": "Named entity: ExponentialE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2147"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fcy", 
+            "description": "Bad named entity: Fcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Fcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fcy;", 
+            "description": "Named entity: Fcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0424"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ffr", 
+            "description": "Bad named entity: Ffr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ffr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ffr;", 
+            "description": "Named entity: Ffr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd09"
+                ]
+            ]
+        }, 
+        {
+            "input": "&FilledSmallSquare", 
+            "description": "Bad named entity: FilledSmallSquare without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&FilledSmallSquare"
+                ]
+            ]
+        }, 
+        {
+            "input": "&FilledSmallSquare;", 
+            "description": "Named entity: FilledSmallSquare; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25fc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&FilledVerySmallSquare", 
+            "description": "Bad named entity: FilledVerySmallSquare without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&FilledVerySmallSquare"
+                ]
+            ]
+        }, 
+        {
+            "input": "&FilledVerySmallSquare;", 
+            "description": "Named entity: FilledVerySmallSquare; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fopf", 
+            "description": "Bad named entity: Fopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Fopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fopf;", 
+            "description": "Named entity: Fopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd3d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ForAll", 
+            "description": "Bad named entity: ForAll without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ForAll"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ForAll;", 
+            "description": "Named entity: ForAll; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2200"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fouriertrf", 
+            "description": "Bad named entity: Fouriertrf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Fouriertrf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fouriertrf;", 
+            "description": "Named entity: Fouriertrf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2131"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fscr", 
+            "description": "Bad named entity: Fscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Fscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Fscr;", 
+            "description": "Named entity: Fscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2131"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GJcy", 
+            "description": "Bad named entity: GJcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GJcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GJcy;", 
+            "description": "Named entity: GJcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0403"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GT", 
+            "description": "Named entity: GT without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    ">"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GT;", 
+            "description": "Named entity: GT; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    ">"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gamma", 
+            "description": "Bad named entity: Gamma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gamma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gamma;", 
+            "description": "Named entity: Gamma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0393"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gammad", 
+            "description": "Bad named entity: Gammad without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gammad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gammad;", 
+            "description": "Named entity: Gammad; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gbreve", 
+            "description": "Bad named entity: Gbreve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gbreve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gbreve;", 
+            "description": "Named entity: Gbreve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u011e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gcedil", 
+            "description": "Bad named entity: Gcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gcedil;", 
+            "description": "Named entity: Gcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0122"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gcirc", 
+            "description": "Bad named entity: Gcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gcirc;", 
+            "description": "Named entity: Gcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u011c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gcy", 
+            "description": "Bad named entity: Gcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gcy;", 
+            "description": "Named entity: Gcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0413"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gdot", 
+            "description": "Bad named entity: Gdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gdot;", 
+            "description": "Named entity: Gdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0120"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gfr", 
+            "description": "Bad named entity: Gfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gfr;", 
+            "description": "Named entity: Gfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd0a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gg", 
+            "description": "Bad named entity: Gg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gg;", 
+            "description": "Named entity: Gg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gopf", 
+            "description": "Bad named entity: Gopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gopf;", 
+            "description": "Named entity: Gopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd3e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterEqual", 
+            "description": "Bad named entity: GreaterEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GreaterEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterEqual;", 
+            "description": "Named entity: GreaterEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2265"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterEqualLess", 
+            "description": "Bad named entity: GreaterEqualLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GreaterEqualLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterEqualLess;", 
+            "description": "Named entity: GreaterEqualLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterFullEqual", 
+            "description": "Bad named entity: GreaterFullEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GreaterFullEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterFullEqual;", 
+            "description": "Named entity: GreaterFullEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2267"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterGreater", 
+            "description": "Bad named entity: GreaterGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GreaterGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterGreater;", 
+            "description": "Named entity: GreaterGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterLess", 
+            "description": "Bad named entity: GreaterLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GreaterLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterLess;", 
+            "description": "Named entity: GreaterLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2277"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterSlantEqual", 
+            "description": "Bad named entity: GreaterSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GreaterSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterSlantEqual;", 
+            "description": "Named entity: GreaterSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterTilde", 
+            "description": "Bad named entity: GreaterTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&GreaterTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&GreaterTilde;", 
+            "description": "Named entity: GreaterTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2273"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gscr", 
+            "description": "Bad named entity: Gscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gscr;", 
+            "description": "Named entity: Gscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udca2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gt", 
+            "description": "Bad named entity: Gt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Gt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Gt;", 
+            "description": "Named entity: Gt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HARDcy", 
+            "description": "Bad named entity: HARDcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&HARDcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HARDcy;", 
+            "description": "Named entity: HARDcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u042a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hacek", 
+            "description": "Bad named entity: Hacek without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Hacek"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hacek;", 
+            "description": "Named entity: Hacek; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hat", 
+            "description": "Bad named entity: Hat without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Hat"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hat;", 
+            "description": "Named entity: Hat; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "^"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hcirc", 
+            "description": "Bad named entity: Hcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Hcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hcirc;", 
+            "description": "Named entity: Hcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0124"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hfr", 
+            "description": "Bad named entity: Hfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Hfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hfr;", 
+            "description": "Named entity: Hfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HilbertSpace", 
+            "description": "Bad named entity: HilbertSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&HilbertSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HilbertSpace;", 
+            "description": "Named entity: HilbertSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hopf", 
+            "description": "Bad named entity: Hopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Hopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hopf;", 
+            "description": "Named entity: Hopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HorizontalLine", 
+            "description": "Bad named entity: HorizontalLine without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&HorizontalLine"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HorizontalLine;", 
+            "description": "Named entity: HorizontalLine; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2500"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hscr", 
+            "description": "Bad named entity: Hscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Hscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hscr;", 
+            "description": "Named entity: Hscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hstrok", 
+            "description": "Bad named entity: Hstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Hstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Hstrok;", 
+            "description": "Named entity: Hstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0126"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HumpDownHump", 
+            "description": "Bad named entity: HumpDownHump without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&HumpDownHump"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HumpDownHump;", 
+            "description": "Named entity: HumpDownHump; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HumpEqual", 
+            "description": "Bad named entity: HumpEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&HumpEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&HumpEqual;", 
+            "description": "Named entity: HumpEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&IEcy", 
+            "description": "Bad named entity: IEcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&IEcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&IEcy;", 
+            "description": "Named entity: IEcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0415"
+                ]
+            ]
+        }, 
+        {
+            "input": "&IJlig", 
+            "description": "Bad named entity: IJlig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&IJlig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&IJlig;", 
+            "description": "Named entity: IJlig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0132"
+                ]
+            ]
+        }, 
+        {
+            "input": "&IOcy", 
+            "description": "Bad named entity: IOcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&IOcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&IOcy;", 
+            "description": "Named entity: IOcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0401"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iacute", 
+            "description": "Named entity: Iacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00cd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iacute;", 
+            "description": "Named entity: Iacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00cd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Icirc", 
+            "description": "Named entity: Icirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Icirc;", 
+            "description": "Named entity: Icirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Icy", 
+            "description": "Bad named entity: Icy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Icy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Icy;", 
+            "description": "Named entity: Icy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0418"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Idot", 
+            "description": "Bad named entity: Idot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Idot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Idot;", 
+            "description": "Named entity: Idot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0130"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ifr", 
+            "description": "Bad named entity: Ifr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ifr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ifr;", 
+            "description": "Named entity: Ifr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2111"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Igrave", 
+            "description": "Named entity: Igrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00cc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Igrave;", 
+            "description": "Named entity: Igrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00cc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Im", 
+            "description": "Bad named entity: Im without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Im"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Im;", 
+            "description": "Named entity: Im; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2111"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Imacr", 
+            "description": "Bad named entity: Imacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Imacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Imacr;", 
+            "description": "Named entity: Imacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u012a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ImaginaryI", 
+            "description": "Bad named entity: ImaginaryI without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ImaginaryI"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ImaginaryI;", 
+            "description": "Named entity: ImaginaryI; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2148"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Implies", 
+            "description": "Bad named entity: Implies without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Implies"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Implies;", 
+            "description": "Named entity: Implies; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Int", 
+            "description": "Bad named entity: Int without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Int"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Int;", 
+            "description": "Named entity: Int; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Integral", 
+            "description": "Bad named entity: Integral without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Integral"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Integral;", 
+            "description": "Named entity: Integral; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Intersection", 
+            "description": "Bad named entity: Intersection without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Intersection"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Intersection;", 
+            "description": "Named entity: Intersection; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&InvisibleComma", 
+            "description": "Bad named entity: InvisibleComma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&InvisibleComma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&InvisibleComma;", 
+            "description": "Named entity: InvisibleComma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2063"
+                ]
+            ]
+        }, 
+        {
+            "input": "&InvisibleTimes", 
+            "description": "Bad named entity: InvisibleTimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&InvisibleTimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&InvisibleTimes;", 
+            "description": "Named entity: InvisibleTimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2062"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iogon", 
+            "description": "Bad named entity: Iogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Iogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iogon;", 
+            "description": "Named entity: Iogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u012e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iopf", 
+            "description": "Bad named entity: Iopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Iopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iopf;", 
+            "description": "Named entity: Iopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd40"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iota", 
+            "description": "Bad named entity: Iota without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Iota"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iota;", 
+            "description": "Named entity: Iota; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0399"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iscr", 
+            "description": "Bad named entity: Iscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Iscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iscr;", 
+            "description": "Named entity: Iscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2110"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Itilde", 
+            "description": "Bad named entity: Itilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Itilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Itilde;", 
+            "description": "Named entity: Itilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0128"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iukcy", 
+            "description": "Bad named entity: Iukcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Iukcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iukcy;", 
+            "description": "Named entity: Iukcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0406"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iuml", 
+            "description": "Named entity: Iuml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00cf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Iuml;", 
+            "description": "Named entity: Iuml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00cf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jcirc", 
+            "description": "Bad named entity: Jcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Jcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jcirc;", 
+            "description": "Named entity: Jcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0134"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jcy", 
+            "description": "Bad named entity: Jcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Jcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jcy;", 
+            "description": "Named entity: Jcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0419"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jfr", 
+            "description": "Bad named entity: Jfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Jfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jfr;", 
+            "description": "Named entity: Jfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd0d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jopf", 
+            "description": "Bad named entity: Jopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Jopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jopf;", 
+            "description": "Named entity: Jopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd41"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jscr", 
+            "description": "Bad named entity: Jscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Jscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jscr;", 
+            "description": "Named entity: Jscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udca5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jsercy", 
+            "description": "Bad named entity: Jsercy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Jsercy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jsercy;", 
+            "description": "Named entity: Jsercy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0408"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jukcy", 
+            "description": "Bad named entity: Jukcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Jukcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Jukcy;", 
+            "description": "Named entity: Jukcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0404"
+                ]
+            ]
+        }, 
+        {
+            "input": "&KHcy", 
+            "description": "Bad named entity: KHcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&KHcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&KHcy;", 
+            "description": "Named entity: KHcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0425"
+                ]
+            ]
+        }, 
+        {
+            "input": "&KJcy", 
+            "description": "Bad named entity: KJcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&KJcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&KJcy;", 
+            "description": "Named entity: KJcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u040c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kappa", 
+            "description": "Bad named entity: Kappa without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Kappa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kappa;", 
+            "description": "Named entity: Kappa; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u039a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kcedil", 
+            "description": "Bad named entity: Kcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Kcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kcedil;", 
+            "description": "Named entity: Kcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0136"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kcy", 
+            "description": "Bad named entity: Kcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Kcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kcy;", 
+            "description": "Named entity: Kcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u041a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kfr", 
+            "description": "Bad named entity: Kfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Kfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kfr;", 
+            "description": "Named entity: Kfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd0e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kopf", 
+            "description": "Bad named entity: Kopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Kopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kopf;", 
+            "description": "Named entity: Kopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd42"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kscr", 
+            "description": "Bad named entity: Kscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Kscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Kscr;", 
+            "description": "Named entity: Kscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udca6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LJcy", 
+            "description": "Bad named entity: LJcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LJcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LJcy;", 
+            "description": "Named entity: LJcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0409"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LT", 
+            "description": "Named entity: LT without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "<"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LT;", 
+            "description": "Named entity: LT; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "<"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lacute", 
+            "description": "Bad named entity: Lacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lacute;", 
+            "description": "Named entity: Lacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0139"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lambda", 
+            "description": "Bad named entity: Lambda without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lambda"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lambda;", 
+            "description": "Named entity: Lambda; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u039b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lang", 
+            "description": "Bad named entity: Lang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lang;", 
+            "description": "Named entity: Lang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27ea"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Laplacetrf", 
+            "description": "Bad named entity: Laplacetrf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Laplacetrf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Laplacetrf;", 
+            "description": "Named entity: Laplacetrf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2112"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Larr", 
+            "description": "Bad named entity: Larr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Larr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Larr;", 
+            "description": "Named entity: Larr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lcaron", 
+            "description": "Bad named entity: Lcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lcaron;", 
+            "description": "Named entity: Lcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u013d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lcedil", 
+            "description": "Bad named entity: Lcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lcedil;", 
+            "description": "Named entity: Lcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u013b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lcy", 
+            "description": "Bad named entity: Lcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lcy;", 
+            "description": "Named entity: Lcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u041b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftAngleBracket", 
+            "description": "Bad named entity: LeftAngleBracket without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftAngleBracket"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftAngleBracket;", 
+            "description": "Named entity: LeftAngleBracket; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftArrow", 
+            "description": "Bad named entity: LeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftArrow;", 
+            "description": "Named entity: LeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2190"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftArrowBar", 
+            "description": "Bad named entity: LeftArrowBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftArrowBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftArrowBar;", 
+            "description": "Named entity: LeftArrowBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21e4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftArrowRightArrow", 
+            "description": "Bad named entity: LeftArrowRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftArrowRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftArrowRightArrow;", 
+            "description": "Named entity: LeftArrowRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftCeiling", 
+            "description": "Bad named entity: LeftCeiling without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftCeiling"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftCeiling;", 
+            "description": "Named entity: LeftCeiling; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2308"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDoubleBracket", 
+            "description": "Bad named entity: LeftDoubleBracket without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftDoubleBracket"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDoubleBracket;", 
+            "description": "Named entity: LeftDoubleBracket; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDownTeeVector", 
+            "description": "Bad named entity: LeftDownTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftDownTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDownTeeVector;", 
+            "description": "Named entity: LeftDownTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2961"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDownVector", 
+            "description": "Bad named entity: LeftDownVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftDownVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDownVector;", 
+            "description": "Named entity: LeftDownVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDownVectorBar", 
+            "description": "Bad named entity: LeftDownVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftDownVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftDownVectorBar;", 
+            "description": "Named entity: LeftDownVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2959"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftFloor", 
+            "description": "Bad named entity: LeftFloor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftFloor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftFloor;", 
+            "description": "Named entity: LeftFloor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftRightArrow", 
+            "description": "Bad named entity: LeftRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftRightArrow;", 
+            "description": "Named entity: LeftRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2194"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftRightVector", 
+            "description": "Bad named entity: LeftRightVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftRightVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftRightVector;", 
+            "description": "Named entity: LeftRightVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u294e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTee", 
+            "description": "Bad named entity: LeftTee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftTee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTee;", 
+            "description": "Named entity: LeftTee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTeeArrow", 
+            "description": "Bad named entity: LeftTeeArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftTeeArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTeeArrow;", 
+            "description": "Named entity: LeftTeeArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTeeVector", 
+            "description": "Bad named entity: LeftTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTeeVector;", 
+            "description": "Named entity: LeftTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u295a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTriangle", 
+            "description": "Bad named entity: LeftTriangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftTriangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTriangle;", 
+            "description": "Named entity: LeftTriangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTriangleBar", 
+            "description": "Bad named entity: LeftTriangleBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftTriangleBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTriangleBar;", 
+            "description": "Named entity: LeftTriangleBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29cf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTriangleEqual", 
+            "description": "Bad named entity: LeftTriangleEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftTriangleEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftTriangleEqual;", 
+            "description": "Named entity: LeftTriangleEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpDownVector", 
+            "description": "Bad named entity: LeftUpDownVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftUpDownVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpDownVector;", 
+            "description": "Named entity: LeftUpDownVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2951"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpTeeVector", 
+            "description": "Bad named entity: LeftUpTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftUpTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpTeeVector;", 
+            "description": "Named entity: LeftUpTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2960"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpVector", 
+            "description": "Bad named entity: LeftUpVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftUpVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpVector;", 
+            "description": "Named entity: LeftUpVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpVectorBar", 
+            "description": "Bad named entity: LeftUpVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftUpVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftUpVectorBar;", 
+            "description": "Named entity: LeftUpVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2958"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftVector", 
+            "description": "Bad named entity: LeftVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftVector;", 
+            "description": "Named entity: LeftVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftVectorBar", 
+            "description": "Bad named entity: LeftVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LeftVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LeftVectorBar;", 
+            "description": "Named entity: LeftVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2952"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Leftarrow", 
+            "description": "Bad named entity: Leftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Leftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Leftarrow;", 
+            "description": "Named entity: Leftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Leftrightarrow", 
+            "description": "Bad named entity: Leftrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Leftrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Leftrightarrow;", 
+            "description": "Named entity: Leftrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessEqualGreater", 
+            "description": "Bad named entity: LessEqualGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LessEqualGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessEqualGreater;", 
+            "description": "Named entity: LessEqualGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessFullEqual", 
+            "description": "Bad named entity: LessFullEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LessFullEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessFullEqual;", 
+            "description": "Named entity: LessFullEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2266"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessGreater", 
+            "description": "Bad named entity: LessGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LessGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessGreater;", 
+            "description": "Named entity: LessGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2276"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessLess", 
+            "description": "Bad named entity: LessLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LessLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessLess;", 
+            "description": "Named entity: LessLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessSlantEqual", 
+            "description": "Bad named entity: LessSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LessSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessSlantEqual;", 
+            "description": "Named entity: LessSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessTilde", 
+            "description": "Bad named entity: LessTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LessTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LessTilde;", 
+            "description": "Named entity: LessTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2272"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lfr", 
+            "description": "Bad named entity: Lfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lfr;", 
+            "description": "Named entity: Lfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd0f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ll", 
+            "description": "Bad named entity: Ll without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ll"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ll;", 
+            "description": "Named entity: Ll; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lleftarrow", 
+            "description": "Bad named entity: Lleftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lleftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lleftarrow;", 
+            "description": "Named entity: Lleftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lmidot", 
+            "description": "Bad named entity: Lmidot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lmidot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lmidot;", 
+            "description": "Named entity: Lmidot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u013f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LongLeftArrow", 
+            "description": "Bad named entity: LongLeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LongLeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LongLeftArrow;", 
+            "description": "Named entity: LongLeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LongLeftRightArrow", 
+            "description": "Bad named entity: LongLeftRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LongLeftRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LongLeftRightArrow;", 
+            "description": "Named entity: LongLeftRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LongRightArrow", 
+            "description": "Bad named entity: LongRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LongRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LongRightArrow;", 
+            "description": "Named entity: LongRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Longleftarrow", 
+            "description": "Bad named entity: Longleftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Longleftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Longleftarrow;", 
+            "description": "Named entity: Longleftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Longleftrightarrow", 
+            "description": "Bad named entity: Longleftrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Longleftrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Longleftrightarrow;", 
+            "description": "Named entity: Longleftrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27fa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Longrightarrow", 
+            "description": "Bad named entity: Longrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Longrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Longrightarrow;", 
+            "description": "Named entity: Longrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lopf", 
+            "description": "Bad named entity: Lopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lopf;", 
+            "description": "Named entity: Lopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd43"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LowerLeftArrow", 
+            "description": "Bad named entity: LowerLeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LowerLeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LowerLeftArrow;", 
+            "description": "Named entity: LowerLeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2199"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LowerRightArrow", 
+            "description": "Bad named entity: LowerRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&LowerRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&LowerRightArrow;", 
+            "description": "Named entity: LowerRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2198"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lscr", 
+            "description": "Bad named entity: Lscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lscr;", 
+            "description": "Named entity: Lscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2112"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lsh", 
+            "description": "Bad named entity: Lsh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lsh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lsh;", 
+            "description": "Named entity: Lsh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lstrok", 
+            "description": "Bad named entity: Lstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lstrok;", 
+            "description": "Named entity: Lstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0141"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lt", 
+            "description": "Bad named entity: Lt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Lt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Lt;", 
+            "description": "Named entity: Lt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Map", 
+            "description": "Bad named entity: Map without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Map"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Map;", 
+            "description": "Named entity: Map; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2905"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mcy", 
+            "description": "Bad named entity: Mcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Mcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mcy;", 
+            "description": "Named entity: Mcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u041c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&MediumSpace", 
+            "description": "Bad named entity: MediumSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&MediumSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&MediumSpace;", 
+            "description": "Named entity: MediumSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u205f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mellintrf", 
+            "description": "Bad named entity: Mellintrf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Mellintrf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mellintrf;", 
+            "description": "Named entity: Mellintrf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2133"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mfr", 
+            "description": "Bad named entity: Mfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Mfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mfr;", 
+            "description": "Named entity: Mfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd10"
+                ]
+            ]
+        }, 
+        {
+            "input": "&MinusPlus", 
+            "description": "Bad named entity: MinusPlus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&MinusPlus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&MinusPlus;", 
+            "description": "Named entity: MinusPlus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2213"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mopf", 
+            "description": "Bad named entity: Mopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Mopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mopf;", 
+            "description": "Named entity: Mopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd44"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mscr", 
+            "description": "Bad named entity: Mscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Mscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mscr;", 
+            "description": "Named entity: Mscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2133"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mu", 
+            "description": "Bad named entity: Mu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Mu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Mu;", 
+            "description": "Named entity: Mu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u039c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NJcy", 
+            "description": "Bad named entity: NJcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NJcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NJcy;", 
+            "description": "Named entity: NJcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u040a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nacute", 
+            "description": "Bad named entity: Nacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Nacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nacute;", 
+            "description": "Named entity: Nacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0143"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ncaron", 
+            "description": "Bad named entity: Ncaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ncaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ncaron;", 
+            "description": "Named entity: Ncaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0147"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ncedil", 
+            "description": "Bad named entity: Ncedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ncedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ncedil;", 
+            "description": "Named entity: Ncedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0145"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ncy", 
+            "description": "Bad named entity: Ncy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ncy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ncy;", 
+            "description": "Named entity: Ncy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u041d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeMediumSpace", 
+            "description": "Bad named entity: NegativeMediumSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NegativeMediumSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeMediumSpace;", 
+            "description": "Named entity: NegativeMediumSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeThickSpace", 
+            "description": "Bad named entity: NegativeThickSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NegativeThickSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeThickSpace;", 
+            "description": "Named entity: NegativeThickSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeThinSpace", 
+            "description": "Bad named entity: NegativeThinSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NegativeThinSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeThinSpace;", 
+            "description": "Named entity: NegativeThinSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeVeryThinSpace", 
+            "description": "Bad named entity: NegativeVeryThinSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NegativeVeryThinSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NegativeVeryThinSpace;", 
+            "description": "Named entity: NegativeVeryThinSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NestedGreaterGreater", 
+            "description": "Bad named entity: NestedGreaterGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NestedGreaterGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NestedGreaterGreater;", 
+            "description": "Named entity: NestedGreaterGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NestedLessLess", 
+            "description": "Bad named entity: NestedLessLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NestedLessLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NestedLessLess;", 
+            "description": "Named entity: NestedLessLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NewLine", 
+            "description": "Bad named entity: NewLine without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NewLine"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NewLine;", 
+            "description": "Named entity: NewLine; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\n"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nfr", 
+            "description": "Bad named entity: Nfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Nfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nfr;", 
+            "description": "Named entity: Nfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd11"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NoBreak", 
+            "description": "Bad named entity: NoBreak without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NoBreak"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NoBreak;", 
+            "description": "Named entity: NoBreak; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2060"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NonBreakingSpace", 
+            "description": "Bad named entity: NonBreakingSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NonBreakingSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NonBreakingSpace;", 
+            "description": "Named entity: NonBreakingSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nopf", 
+            "description": "Bad named entity: Nopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Nopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nopf;", 
+            "description": "Named entity: Nopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2115"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Not", 
+            "description": "Bad named entity: Not without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Not"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Not;", 
+            "description": "Named entity: Not; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotCongruent", 
+            "description": "Bad named entity: NotCongruent without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotCongruent"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotCongruent;", 
+            "description": "Named entity: NotCongruent; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2262"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotCupCap", 
+            "description": "Bad named entity: NotCupCap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotCupCap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotCupCap;", 
+            "description": "Named entity: NotCupCap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotDoubleVerticalBar", 
+            "description": "Bad named entity: NotDoubleVerticalBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotDoubleVerticalBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotDoubleVerticalBar;", 
+            "description": "Named entity: NotDoubleVerticalBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2226"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotElement", 
+            "description": "Bad named entity: NotElement without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotElement"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotElement;", 
+            "description": "Named entity: NotElement; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2209"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotEqual", 
+            "description": "Bad named entity: NotEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotEqual;", 
+            "description": "Named entity: NotEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2260"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotEqualTilde", 
+            "description": "Bad named entity: NotEqualTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotEqualTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotEqualTilde;", 
+            "description": "Named entity: NotEqualTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2242\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotExists", 
+            "description": "Bad named entity: NotExists without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotExists"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotExists;", 
+            "description": "Named entity: NotExists; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2204"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreater", 
+            "description": "Bad named entity: NotGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreater;", 
+            "description": "Named entity: NotGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterEqual", 
+            "description": "Bad named entity: NotGreaterEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotGreaterEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterEqual;", 
+            "description": "Named entity: NotGreaterEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2271"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterFullEqual", 
+            "description": "Bad named entity: NotGreaterFullEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotGreaterFullEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterFullEqual;", 
+            "description": "Named entity: NotGreaterFullEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2267\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterGreater", 
+            "description": "Bad named entity: NotGreaterGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotGreaterGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterGreater;", 
+            "description": "Named entity: NotGreaterGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226b\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterLess", 
+            "description": "Bad named entity: NotGreaterLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotGreaterLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterLess;", 
+            "description": "Named entity: NotGreaterLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2279"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterSlantEqual", 
+            "description": "Bad named entity: NotGreaterSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotGreaterSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterSlantEqual;", 
+            "description": "Named entity: NotGreaterSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7e\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterTilde", 
+            "description": "Bad named entity: NotGreaterTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotGreaterTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotGreaterTilde;", 
+            "description": "Named entity: NotGreaterTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2275"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotHumpDownHump", 
+            "description": "Bad named entity: NotHumpDownHump without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotHumpDownHump"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotHumpDownHump;", 
+            "description": "Named entity: NotHumpDownHump; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224e\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotHumpEqual", 
+            "description": "Bad named entity: NotHumpEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotHumpEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotHumpEqual;", 
+            "description": "Named entity: NotHumpEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224f\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLeftTriangle", 
+            "description": "Bad named entity: NotLeftTriangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLeftTriangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLeftTriangle;", 
+            "description": "Named entity: NotLeftTriangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ea"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLeftTriangleBar", 
+            "description": "Bad named entity: NotLeftTriangleBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLeftTriangleBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLeftTriangleBar;", 
+            "description": "Named entity: NotLeftTriangleBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29cf\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLeftTriangleEqual", 
+            "description": "Bad named entity: NotLeftTriangleEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLeftTriangleEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLeftTriangleEqual;", 
+            "description": "Named entity: NotLeftTriangleEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLess", 
+            "description": "Bad named entity: NotLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLess;", 
+            "description": "Named entity: NotLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessEqual", 
+            "description": "Bad named entity: NotLessEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLessEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessEqual;", 
+            "description": "Named entity: NotLessEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2270"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessGreater", 
+            "description": "Bad named entity: NotLessGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLessGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessGreater;", 
+            "description": "Named entity: NotLessGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2278"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessLess", 
+            "description": "Bad named entity: NotLessLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLessLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessLess;", 
+            "description": "Named entity: NotLessLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226a\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessSlantEqual", 
+            "description": "Bad named entity: NotLessSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLessSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessSlantEqual;", 
+            "description": "Named entity: NotLessSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7d\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessTilde", 
+            "description": "Bad named entity: NotLessTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotLessTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotLessTilde;", 
+            "description": "Named entity: NotLessTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2274"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotNestedGreaterGreater", 
+            "description": "Bad named entity: NotNestedGreaterGreater without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotNestedGreaterGreater"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotNestedGreaterGreater;", 
+            "description": "Named entity: NotNestedGreaterGreater; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa2\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotNestedLessLess", 
+            "description": "Bad named entity: NotNestedLessLess without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotNestedLessLess"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotNestedLessLess;", 
+            "description": "Named entity: NotNestedLessLess; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa1\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotPrecedes", 
+            "description": "Bad named entity: NotPrecedes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotPrecedes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotPrecedes;", 
+            "description": "Named entity: NotPrecedes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2280"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotPrecedesEqual", 
+            "description": "Bad named entity: NotPrecedesEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotPrecedesEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotPrecedesEqual;", 
+            "description": "Named entity: NotPrecedesEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aaf\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotPrecedesSlantEqual", 
+            "description": "Bad named entity: NotPrecedesSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotPrecedesSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotPrecedesSlantEqual;", 
+            "description": "Named entity: NotPrecedesSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotReverseElement", 
+            "description": "Bad named entity: NotReverseElement without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotReverseElement"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotReverseElement;", 
+            "description": "Named entity: NotReverseElement; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotRightTriangle", 
+            "description": "Bad named entity: NotRightTriangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotRightTriangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotRightTriangle;", 
+            "description": "Named entity: NotRightTriangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotRightTriangleBar", 
+            "description": "Bad named entity: NotRightTriangleBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotRightTriangleBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotRightTriangleBar;", 
+            "description": "Named entity: NotRightTriangleBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29d0\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotRightTriangleEqual", 
+            "description": "Bad named entity: NotRightTriangleEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotRightTriangleEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotRightTriangleEqual;", 
+            "description": "Named entity: NotRightTriangleEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSubset", 
+            "description": "Bad named entity: NotSquareSubset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSquareSubset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSubset;", 
+            "description": "Named entity: NotSquareSubset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228f\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSubsetEqual", 
+            "description": "Bad named entity: NotSquareSubsetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSquareSubsetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSubsetEqual;", 
+            "description": "Named entity: NotSquareSubsetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSuperset", 
+            "description": "Bad named entity: NotSquareSuperset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSquareSuperset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSuperset;", 
+            "description": "Named entity: NotSquareSuperset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2290\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSupersetEqual", 
+            "description": "Bad named entity: NotSquareSupersetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSquareSupersetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSquareSupersetEqual;", 
+            "description": "Named entity: NotSquareSupersetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSubset", 
+            "description": "Bad named entity: NotSubset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSubset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSubset;", 
+            "description": "Named entity: NotSubset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2282\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSubsetEqual", 
+            "description": "Bad named entity: NotSubsetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSubsetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSubsetEqual;", 
+            "description": "Named entity: NotSubsetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2288"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceeds", 
+            "description": "Bad named entity: NotSucceeds without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSucceeds"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceeds;", 
+            "description": "Named entity: NotSucceeds; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2281"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceedsEqual", 
+            "description": "Bad named entity: NotSucceedsEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSucceedsEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceedsEqual;", 
+            "description": "Named entity: NotSucceedsEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab0\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceedsSlantEqual", 
+            "description": "Bad named entity: NotSucceedsSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSucceedsSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceedsSlantEqual;", 
+            "description": "Named entity: NotSucceedsSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceedsTilde", 
+            "description": "Bad named entity: NotSucceedsTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSucceedsTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSucceedsTilde;", 
+            "description": "Named entity: NotSucceedsTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227f\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSuperset", 
+            "description": "Bad named entity: NotSuperset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSuperset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSuperset;", 
+            "description": "Named entity: NotSuperset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2283\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSupersetEqual", 
+            "description": "Bad named entity: NotSupersetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotSupersetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotSupersetEqual;", 
+            "description": "Named entity: NotSupersetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2289"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTilde", 
+            "description": "Bad named entity: NotTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTilde;", 
+            "description": "Named entity: NotTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2241"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTildeEqual", 
+            "description": "Bad named entity: NotTildeEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotTildeEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTildeEqual;", 
+            "description": "Named entity: NotTildeEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2244"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTildeFullEqual", 
+            "description": "Bad named entity: NotTildeFullEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotTildeFullEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTildeFullEqual;", 
+            "description": "Named entity: NotTildeFullEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2247"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTildeTilde", 
+            "description": "Bad named entity: NotTildeTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotTildeTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotTildeTilde;", 
+            "description": "Named entity: NotTildeTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2249"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotVerticalBar", 
+            "description": "Bad named entity: NotVerticalBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&NotVerticalBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&NotVerticalBar;", 
+            "description": "Named entity: NotVerticalBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2224"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nscr", 
+            "description": "Bad named entity: Nscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Nscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nscr;", 
+            "description": "Named entity: Nscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udca9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ntilde", 
+            "description": "Named entity: Ntilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ntilde;", 
+            "description": "Named entity: Ntilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nu", 
+            "description": "Bad named entity: Nu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Nu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Nu;", 
+            "description": "Named entity: Nu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u039d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OElig", 
+            "description": "Bad named entity: OElig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&OElig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OElig;", 
+            "description": "Named entity: OElig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0152"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oacute", 
+            "description": "Named entity: Oacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oacute;", 
+            "description": "Named entity: Oacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ocirc", 
+            "description": "Named entity: Ocirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ocirc;", 
+            "description": "Named entity: Ocirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ocy", 
+            "description": "Bad named entity: Ocy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ocy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ocy;", 
+            "description": "Named entity: Ocy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u041e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Odblac", 
+            "description": "Bad named entity: Odblac without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Odblac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Odblac;", 
+            "description": "Named entity: Odblac; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0150"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ofr", 
+            "description": "Bad named entity: Ofr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ofr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ofr;", 
+            "description": "Named entity: Ofr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd12"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ograve", 
+            "description": "Named entity: Ograve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ograve;", 
+            "description": "Named entity: Ograve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Omacr", 
+            "description": "Bad named entity: Omacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Omacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Omacr;", 
+            "description": "Named entity: Omacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u014c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Omega", 
+            "description": "Bad named entity: Omega without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Omega"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Omega;", 
+            "description": "Named entity: Omega; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Omicron", 
+            "description": "Bad named entity: Omicron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Omicron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Omicron;", 
+            "description": "Named entity: Omicron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u039f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oopf", 
+            "description": "Bad named entity: Oopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Oopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oopf;", 
+            "description": "Named entity: Oopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd46"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OpenCurlyDoubleQuote", 
+            "description": "Bad named entity: OpenCurlyDoubleQuote without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&OpenCurlyDoubleQuote"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OpenCurlyDoubleQuote;", 
+            "description": "Named entity: OpenCurlyDoubleQuote; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OpenCurlyQuote", 
+            "description": "Bad named entity: OpenCurlyQuote without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&OpenCurlyQuote"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OpenCurlyQuote;", 
+            "description": "Named entity: OpenCurlyQuote; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2018"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Or", 
+            "description": "Bad named entity: Or without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Or"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Or;", 
+            "description": "Named entity: Or; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a54"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oscr", 
+            "description": "Bad named entity: Oscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Oscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oscr;", 
+            "description": "Named entity: Oscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcaa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oslash", 
+            "description": "Named entity: Oslash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Oslash;", 
+            "description": "Named entity: Oslash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Otilde", 
+            "description": "Named entity: Otilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Otilde;", 
+            "description": "Named entity: Otilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Otimes", 
+            "description": "Bad named entity: Otimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Otimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Otimes;", 
+            "description": "Named entity: Otimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a37"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ouml", 
+            "description": "Named entity: Ouml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ouml;", 
+            "description": "Named entity: Ouml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverBar", 
+            "description": "Bad named entity: OverBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&OverBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverBar;", 
+            "description": "Named entity: OverBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u203e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverBrace", 
+            "description": "Bad named entity: OverBrace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&OverBrace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverBrace;", 
+            "description": "Named entity: OverBrace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23de"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverBracket", 
+            "description": "Bad named entity: OverBracket without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&OverBracket"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverBracket;", 
+            "description": "Named entity: OverBracket; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverParenthesis", 
+            "description": "Bad named entity: OverParenthesis without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&OverParenthesis"
+                ]
+            ]
+        }, 
+        {
+            "input": "&OverParenthesis;", 
+            "description": "Named entity: OverParenthesis; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PartialD", 
+            "description": "Bad named entity: PartialD without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&PartialD"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PartialD;", 
+            "description": "Named entity: PartialD; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2202"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pcy", 
+            "description": "Bad named entity: Pcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Pcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pcy;", 
+            "description": "Named entity: Pcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u041f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pfr", 
+            "description": "Bad named entity: Pfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Pfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pfr;", 
+            "description": "Named entity: Pfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd13"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Phi", 
+            "description": "Bad named entity: Phi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Phi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Phi;", 
+            "description": "Named entity: Phi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pi", 
+            "description": "Bad named entity: Pi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Pi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pi;", 
+            "description": "Named entity: Pi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PlusMinus", 
+            "description": "Bad named entity: PlusMinus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&PlusMinus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PlusMinus;", 
+            "description": "Named entity: PlusMinus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Poincareplane", 
+            "description": "Bad named entity: Poincareplane without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Poincareplane"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Poincareplane;", 
+            "description": "Named entity: Poincareplane; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Popf", 
+            "description": "Bad named entity: Popf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Popf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Popf;", 
+            "description": "Named entity: Popf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2119"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pr", 
+            "description": "Bad named entity: Pr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Pr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pr;", 
+            "description": "Named entity: Pr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2abb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Precedes", 
+            "description": "Bad named entity: Precedes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Precedes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Precedes;", 
+            "description": "Named entity: Precedes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PrecedesEqual", 
+            "description": "Bad named entity: PrecedesEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&PrecedesEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PrecedesEqual;", 
+            "description": "Named entity: PrecedesEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aaf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PrecedesSlantEqual", 
+            "description": "Bad named entity: PrecedesSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&PrecedesSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PrecedesSlantEqual;", 
+            "description": "Named entity: PrecedesSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PrecedesTilde", 
+            "description": "Bad named entity: PrecedesTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&PrecedesTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&PrecedesTilde;", 
+            "description": "Named entity: PrecedesTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Prime", 
+            "description": "Bad named entity: Prime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Prime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Prime;", 
+            "description": "Named entity: Prime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2033"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Product", 
+            "description": "Bad named entity: Product without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Product"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Product;", 
+            "description": "Named entity: Product; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Proportion", 
+            "description": "Bad named entity: Proportion without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Proportion"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Proportion;", 
+            "description": "Named entity: Proportion; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2237"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Proportional", 
+            "description": "Bad named entity: Proportional without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Proportional"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Proportional;", 
+            "description": "Named entity: Proportional; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pscr", 
+            "description": "Bad named entity: Pscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Pscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Pscr;", 
+            "description": "Named entity: Pscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Psi", 
+            "description": "Bad named entity: Psi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Psi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Psi;", 
+            "description": "Named entity: Psi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&QUOT", 
+            "description": "Named entity: QUOT without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\""
+                ]
+            ]
+        }, 
+        {
+            "input": "&QUOT;", 
+            "description": "Named entity: QUOT; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\""
+                ]
+            ]
+        }, 
+        {
+            "input": "&Qfr", 
+            "description": "Bad named entity: Qfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Qfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Qfr;", 
+            "description": "Named entity: Qfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd14"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Qopf", 
+            "description": "Bad named entity: Qopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Qopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Qopf;", 
+            "description": "Named entity: Qopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Qscr", 
+            "description": "Bad named entity: Qscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Qscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Qscr;", 
+            "description": "Named entity: Qscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RBarr", 
+            "description": "Bad named entity: RBarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RBarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RBarr;", 
+            "description": "Named entity: RBarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2910"
+                ]
+            ]
+        }, 
+        {
+            "input": "&REG", 
+            "description": "Named entity: REG without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&REG;", 
+            "description": "Named entity: REG; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Racute", 
+            "description": "Bad named entity: Racute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Racute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Racute;", 
+            "description": "Named entity: Racute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0154"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rang", 
+            "description": "Bad named entity: Rang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rang;", 
+            "description": "Named entity: Rang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rarr", 
+            "description": "Bad named entity: Rarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rarr;", 
+            "description": "Named entity: Rarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rarrtl", 
+            "description": "Bad named entity: Rarrtl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rarrtl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rarrtl;", 
+            "description": "Named entity: Rarrtl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2916"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rcaron", 
+            "description": "Bad named entity: Rcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rcaron;", 
+            "description": "Named entity: Rcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0158"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rcedil", 
+            "description": "Bad named entity: Rcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rcedil;", 
+            "description": "Named entity: Rcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0156"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rcy", 
+            "description": "Bad named entity: Rcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rcy;", 
+            "description": "Named entity: Rcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0420"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Re", 
+            "description": "Bad named entity: Re without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Re"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Re;", 
+            "description": "Named entity: Re; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ReverseElement", 
+            "description": "Bad named entity: ReverseElement without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ReverseElement"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ReverseElement;", 
+            "description": "Named entity: ReverseElement; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ReverseEquilibrium", 
+            "description": "Bad named entity: ReverseEquilibrium without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ReverseEquilibrium"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ReverseEquilibrium;", 
+            "description": "Named entity: ReverseEquilibrium; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ReverseUpEquilibrium", 
+            "description": "Bad named entity: ReverseUpEquilibrium without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ReverseUpEquilibrium"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ReverseUpEquilibrium;", 
+            "description": "Named entity: ReverseUpEquilibrium; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rfr", 
+            "description": "Bad named entity: Rfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rfr;", 
+            "description": "Named entity: Rfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rho", 
+            "description": "Bad named entity: Rho without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rho"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rho;", 
+            "description": "Named entity: Rho; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightAngleBracket", 
+            "description": "Bad named entity: RightAngleBracket without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightAngleBracket"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightAngleBracket;", 
+            "description": "Named entity: RightAngleBracket; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightArrow", 
+            "description": "Bad named entity: RightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightArrow;", 
+            "description": "Named entity: RightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2192"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightArrowBar", 
+            "description": "Bad named entity: RightArrowBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightArrowBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightArrowBar;", 
+            "description": "Named entity: RightArrowBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightArrowLeftArrow", 
+            "description": "Bad named entity: RightArrowLeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightArrowLeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightArrowLeftArrow;", 
+            "description": "Named entity: RightArrowLeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightCeiling", 
+            "description": "Bad named entity: RightCeiling without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightCeiling"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightCeiling;", 
+            "description": "Named entity: RightCeiling; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2309"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDoubleBracket", 
+            "description": "Bad named entity: RightDoubleBracket without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightDoubleBracket"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDoubleBracket;", 
+            "description": "Named entity: RightDoubleBracket; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDownTeeVector", 
+            "description": "Bad named entity: RightDownTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightDownTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDownTeeVector;", 
+            "description": "Named entity: RightDownTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u295d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDownVector", 
+            "description": "Bad named entity: RightDownVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightDownVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDownVector;", 
+            "description": "Named entity: RightDownVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDownVectorBar", 
+            "description": "Bad named entity: RightDownVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightDownVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightDownVectorBar;", 
+            "description": "Named entity: RightDownVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2955"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightFloor", 
+            "description": "Bad named entity: RightFloor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightFloor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightFloor;", 
+            "description": "Named entity: RightFloor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTee", 
+            "description": "Bad named entity: RightTee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightTee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTee;", 
+            "description": "Named entity: RightTee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTeeArrow", 
+            "description": "Bad named entity: RightTeeArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightTeeArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTeeArrow;", 
+            "description": "Named entity: RightTeeArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTeeVector", 
+            "description": "Bad named entity: RightTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTeeVector;", 
+            "description": "Named entity: RightTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u295b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTriangle", 
+            "description": "Bad named entity: RightTriangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightTriangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTriangle;", 
+            "description": "Named entity: RightTriangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTriangleBar", 
+            "description": "Bad named entity: RightTriangleBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightTriangleBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTriangleBar;", 
+            "description": "Named entity: RightTriangleBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTriangleEqual", 
+            "description": "Bad named entity: RightTriangleEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightTriangleEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightTriangleEqual;", 
+            "description": "Named entity: RightTriangleEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpDownVector", 
+            "description": "Bad named entity: RightUpDownVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightUpDownVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpDownVector;", 
+            "description": "Named entity: RightUpDownVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u294f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpTeeVector", 
+            "description": "Bad named entity: RightUpTeeVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightUpTeeVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpTeeVector;", 
+            "description": "Named entity: RightUpTeeVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u295c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpVector", 
+            "description": "Bad named entity: RightUpVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightUpVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpVector;", 
+            "description": "Named entity: RightUpVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpVectorBar", 
+            "description": "Bad named entity: RightUpVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightUpVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightUpVectorBar;", 
+            "description": "Named entity: RightUpVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2954"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightVector", 
+            "description": "Bad named entity: RightVector without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightVector"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightVector;", 
+            "description": "Named entity: RightVector; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightVectorBar", 
+            "description": "Bad named entity: RightVectorBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RightVectorBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RightVectorBar;", 
+            "description": "Named entity: RightVectorBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2953"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rightarrow", 
+            "description": "Bad named entity: Rightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rightarrow;", 
+            "description": "Named entity: Rightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ropf", 
+            "description": "Bad named entity: Ropf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ropf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ropf;", 
+            "description": "Named entity: Ropf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RoundImplies", 
+            "description": "Bad named entity: RoundImplies without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RoundImplies"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RoundImplies;", 
+            "description": "Named entity: RoundImplies; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2970"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rrightarrow", 
+            "description": "Bad named entity: Rrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rrightarrow;", 
+            "description": "Named entity: Rrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rscr", 
+            "description": "Bad named entity: Rscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rscr;", 
+            "description": "Named entity: Rscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rsh", 
+            "description": "Bad named entity: Rsh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Rsh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Rsh;", 
+            "description": "Named entity: Rsh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RuleDelayed", 
+            "description": "Bad named entity: RuleDelayed without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&RuleDelayed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&RuleDelayed;", 
+            "description": "Named entity: RuleDelayed; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29f4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SHCHcy", 
+            "description": "Bad named entity: SHCHcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SHCHcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SHCHcy;", 
+            "description": "Named entity: SHCHcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0429"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SHcy", 
+            "description": "Bad named entity: SHcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SHcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SHcy;", 
+            "description": "Named entity: SHcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0428"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SOFTcy", 
+            "description": "Bad named entity: SOFTcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SOFTcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SOFTcy;", 
+            "description": "Named entity: SOFTcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u042c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sacute", 
+            "description": "Bad named entity: Sacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sacute;", 
+            "description": "Named entity: Sacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u015a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sc", 
+            "description": "Bad named entity: Sc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sc;", 
+            "description": "Named entity: Sc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2abc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scaron", 
+            "description": "Bad named entity: Scaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Scaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scaron;", 
+            "description": "Named entity: Scaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0160"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scedil", 
+            "description": "Bad named entity: Scedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Scedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scedil;", 
+            "description": "Named entity: Scedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u015e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scirc", 
+            "description": "Bad named entity: Scirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Scirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scirc;", 
+            "description": "Named entity: Scirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u015c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scy", 
+            "description": "Bad named entity: Scy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Scy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Scy;", 
+            "description": "Named entity: Scy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0421"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sfr", 
+            "description": "Bad named entity: Sfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sfr;", 
+            "description": "Named entity: Sfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd16"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortDownArrow", 
+            "description": "Bad named entity: ShortDownArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ShortDownArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortDownArrow;", 
+            "description": "Named entity: ShortDownArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2193"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortLeftArrow", 
+            "description": "Bad named entity: ShortLeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ShortLeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortLeftArrow;", 
+            "description": "Named entity: ShortLeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2190"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortRightArrow", 
+            "description": "Bad named entity: ShortRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ShortRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortRightArrow;", 
+            "description": "Named entity: ShortRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2192"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortUpArrow", 
+            "description": "Bad named entity: ShortUpArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ShortUpArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ShortUpArrow;", 
+            "description": "Named entity: ShortUpArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2191"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sigma", 
+            "description": "Bad named entity: Sigma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sigma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sigma;", 
+            "description": "Named entity: Sigma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SmallCircle", 
+            "description": "Bad named entity: SmallCircle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SmallCircle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SmallCircle;", 
+            "description": "Named entity: SmallCircle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2218"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sopf", 
+            "description": "Bad named entity: Sopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sopf;", 
+            "description": "Named entity: Sopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd4a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sqrt", 
+            "description": "Bad named entity: Sqrt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sqrt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sqrt;", 
+            "description": "Named entity: Sqrt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Square", 
+            "description": "Bad named entity: Square without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Square"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Square;", 
+            "description": "Named entity: Square; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareIntersection", 
+            "description": "Bad named entity: SquareIntersection without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SquareIntersection"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareIntersection;", 
+            "description": "Named entity: SquareIntersection; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2293"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSubset", 
+            "description": "Bad named entity: SquareSubset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SquareSubset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSubset;", 
+            "description": "Named entity: SquareSubset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSubsetEqual", 
+            "description": "Bad named entity: SquareSubsetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SquareSubsetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSubsetEqual;", 
+            "description": "Named entity: SquareSubsetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2291"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSuperset", 
+            "description": "Bad named entity: SquareSuperset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SquareSuperset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSuperset;", 
+            "description": "Named entity: SquareSuperset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2290"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSupersetEqual", 
+            "description": "Bad named entity: SquareSupersetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SquareSupersetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareSupersetEqual;", 
+            "description": "Named entity: SquareSupersetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2292"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareUnion", 
+            "description": "Bad named entity: SquareUnion without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SquareUnion"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SquareUnion;", 
+            "description": "Named entity: SquareUnion; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2294"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sscr", 
+            "description": "Bad named entity: Sscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sscr;", 
+            "description": "Named entity: Sscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Star", 
+            "description": "Bad named entity: Star without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Star"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Star;", 
+            "description": "Named entity: Star; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sub", 
+            "description": "Bad named entity: Sub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sub;", 
+            "description": "Named entity: Sub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Subset", 
+            "description": "Bad named entity: Subset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Subset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Subset;", 
+            "description": "Named entity: Subset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SubsetEqual", 
+            "description": "Bad named entity: SubsetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SubsetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SubsetEqual;", 
+            "description": "Named entity: SubsetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2286"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Succeeds", 
+            "description": "Bad named entity: Succeeds without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Succeeds"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Succeeds;", 
+            "description": "Named entity: Succeeds; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SucceedsEqual", 
+            "description": "Bad named entity: SucceedsEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SucceedsEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SucceedsEqual;", 
+            "description": "Named entity: SucceedsEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SucceedsSlantEqual", 
+            "description": "Bad named entity: SucceedsSlantEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SucceedsSlantEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SucceedsSlantEqual;", 
+            "description": "Named entity: SucceedsSlantEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SucceedsTilde", 
+            "description": "Bad named entity: SucceedsTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SucceedsTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SucceedsTilde;", 
+            "description": "Named entity: SucceedsTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SuchThat", 
+            "description": "Bad named entity: SuchThat without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SuchThat"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SuchThat;", 
+            "description": "Named entity: SuchThat; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sum", 
+            "description": "Bad named entity: Sum without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sum"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sum;", 
+            "description": "Named entity: Sum; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2211"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sup", 
+            "description": "Bad named entity: Sup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Sup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Sup;", 
+            "description": "Named entity: Sup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Superset", 
+            "description": "Bad named entity: Superset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Superset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Superset;", 
+            "description": "Named entity: Superset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2283"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SupersetEqual", 
+            "description": "Bad named entity: SupersetEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&SupersetEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&SupersetEqual;", 
+            "description": "Named entity: SupersetEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2287"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Supset", 
+            "description": "Bad named entity: Supset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Supset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Supset;", 
+            "description": "Named entity: Supset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&THORN", 
+            "description": "Named entity: THORN without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00de"
+                ]
+            ]
+        }, 
+        {
+            "input": "&THORN;", 
+            "description": "Named entity: THORN; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00de"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TRADE", 
+            "description": "Bad named entity: TRADE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&TRADE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TRADE;", 
+            "description": "Named entity: TRADE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2122"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TSHcy", 
+            "description": "Bad named entity: TSHcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&TSHcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TSHcy;", 
+            "description": "Named entity: TSHcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u040b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TScy", 
+            "description": "Bad named entity: TScy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&TScy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TScy;", 
+            "description": "Named entity: TScy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0426"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tab", 
+            "description": "Bad named entity: Tab without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tab;", 
+            "description": "Named entity: Tab; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\t"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tau", 
+            "description": "Bad named entity: Tau without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tau"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tau;", 
+            "description": "Named entity: Tau; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tcaron", 
+            "description": "Bad named entity: Tcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tcaron;", 
+            "description": "Named entity: Tcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0164"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tcedil", 
+            "description": "Bad named entity: Tcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tcedil;", 
+            "description": "Named entity: Tcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0162"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tcy", 
+            "description": "Bad named entity: Tcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tcy;", 
+            "description": "Named entity: Tcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0422"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tfr", 
+            "description": "Bad named entity: Tfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tfr;", 
+            "description": "Named entity: Tfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd17"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Therefore", 
+            "description": "Bad named entity: Therefore without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Therefore"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Therefore;", 
+            "description": "Named entity: Therefore; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2234"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Theta", 
+            "description": "Bad named entity: Theta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Theta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Theta;", 
+            "description": "Named entity: Theta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0398"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ThickSpace", 
+            "description": "Bad named entity: ThickSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ThickSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ThickSpace;", 
+            "description": "Named entity: ThickSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u205f\u200a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ThinSpace", 
+            "description": "Bad named entity: ThinSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ThinSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ThinSpace;", 
+            "description": "Named entity: ThinSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2009"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tilde", 
+            "description": "Bad named entity: Tilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tilde;", 
+            "description": "Named entity: Tilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TildeEqual", 
+            "description": "Bad named entity: TildeEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&TildeEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TildeEqual;", 
+            "description": "Named entity: TildeEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2243"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TildeFullEqual", 
+            "description": "Bad named entity: TildeFullEqual without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&TildeFullEqual"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TildeFullEqual;", 
+            "description": "Named entity: TildeFullEqual; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2245"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TildeTilde", 
+            "description": "Bad named entity: TildeTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&TildeTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TildeTilde;", 
+            "description": "Named entity: TildeTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2248"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Topf", 
+            "description": "Bad named entity: Topf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Topf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Topf;", 
+            "description": "Named entity: Topf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd4b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TripleDot", 
+            "description": "Bad named entity: TripleDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&TripleDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&TripleDot;", 
+            "description": "Named entity: TripleDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u20db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tscr", 
+            "description": "Bad named entity: Tscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tscr;", 
+            "description": "Named entity: Tscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcaf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tstrok", 
+            "description": "Bad named entity: Tstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Tstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Tstrok;", 
+            "description": "Named entity: Tstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0166"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uacute", 
+            "description": "Named entity: Uacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uacute;", 
+            "description": "Named entity: Uacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uarr", 
+            "description": "Bad named entity: Uarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Uarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uarr;", 
+            "description": "Named entity: Uarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uarrocir", 
+            "description": "Bad named entity: Uarrocir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Uarrocir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uarrocir;", 
+            "description": "Named entity: Uarrocir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2949"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ubrcy", 
+            "description": "Bad named entity: Ubrcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ubrcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ubrcy;", 
+            "description": "Named entity: Ubrcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u040e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ubreve", 
+            "description": "Bad named entity: Ubreve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ubreve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ubreve;", 
+            "description": "Named entity: Ubreve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u016c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ucirc", 
+            "description": "Named entity: Ucirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ucirc;", 
+            "description": "Named entity: Ucirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ucy", 
+            "description": "Bad named entity: Ucy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ucy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ucy;", 
+            "description": "Named entity: Ucy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0423"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Udblac", 
+            "description": "Bad named entity: Udblac without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Udblac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Udblac;", 
+            "description": "Named entity: Udblac; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0170"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ufr", 
+            "description": "Bad named entity: Ufr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ufr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ufr;", 
+            "description": "Named entity: Ufr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd18"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ugrave", 
+            "description": "Named entity: Ugrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ugrave;", 
+            "description": "Named entity: Ugrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Umacr", 
+            "description": "Bad named entity: Umacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Umacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Umacr;", 
+            "description": "Named entity: Umacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u016a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderBar", 
+            "description": "Bad named entity: UnderBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UnderBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderBar;", 
+            "description": "Named entity: UnderBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "_"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderBrace", 
+            "description": "Bad named entity: UnderBrace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UnderBrace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderBrace;", 
+            "description": "Named entity: UnderBrace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23df"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderBracket", 
+            "description": "Bad named entity: UnderBracket without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UnderBracket"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderBracket;", 
+            "description": "Named entity: UnderBracket; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderParenthesis", 
+            "description": "Bad named entity: UnderParenthesis without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UnderParenthesis"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnderParenthesis;", 
+            "description": "Named entity: UnderParenthesis; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Union", 
+            "description": "Bad named entity: Union without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Union"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Union;", 
+            "description": "Named entity: Union; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnionPlus", 
+            "description": "Bad named entity: UnionPlus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UnionPlus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UnionPlus;", 
+            "description": "Named entity: UnionPlus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uogon", 
+            "description": "Bad named entity: Uogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Uogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uogon;", 
+            "description": "Named entity: Uogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0172"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uopf", 
+            "description": "Bad named entity: Uopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Uopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uopf;", 
+            "description": "Named entity: Uopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd4c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpArrow", 
+            "description": "Bad named entity: UpArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpArrow;", 
+            "description": "Named entity: UpArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2191"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpArrowBar", 
+            "description": "Bad named entity: UpArrowBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpArrowBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpArrowBar;", 
+            "description": "Named entity: UpArrowBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2912"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpArrowDownArrow", 
+            "description": "Bad named entity: UpArrowDownArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpArrowDownArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpArrowDownArrow;", 
+            "description": "Named entity: UpArrowDownArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpDownArrow", 
+            "description": "Bad named entity: UpDownArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpDownArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpDownArrow;", 
+            "description": "Named entity: UpDownArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2195"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpEquilibrium", 
+            "description": "Bad named entity: UpEquilibrium without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpEquilibrium"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpEquilibrium;", 
+            "description": "Named entity: UpEquilibrium; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpTee", 
+            "description": "Bad named entity: UpTee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpTee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpTee;", 
+            "description": "Named entity: UpTee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpTeeArrow", 
+            "description": "Bad named entity: UpTeeArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpTeeArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpTeeArrow;", 
+            "description": "Named entity: UpTeeArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uparrow", 
+            "description": "Bad named entity: Uparrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Uparrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uparrow;", 
+            "description": "Named entity: Uparrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Updownarrow", 
+            "description": "Bad named entity: Updownarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Updownarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Updownarrow;", 
+            "description": "Named entity: Updownarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpperLeftArrow", 
+            "description": "Bad named entity: UpperLeftArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpperLeftArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpperLeftArrow;", 
+            "description": "Named entity: UpperLeftArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2196"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpperRightArrow", 
+            "description": "Bad named entity: UpperRightArrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&UpperRightArrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&UpperRightArrow;", 
+            "description": "Named entity: UpperRightArrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2197"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Upsi", 
+            "description": "Bad named entity: Upsi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Upsi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Upsi;", 
+            "description": "Named entity: Upsi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Upsilon", 
+            "description": "Bad named entity: Upsilon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Upsilon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Upsilon;", 
+            "description": "Named entity: Upsilon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uring", 
+            "description": "Bad named entity: Uring without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Uring"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uring;", 
+            "description": "Named entity: Uring; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u016e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uscr", 
+            "description": "Bad named entity: Uscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Uscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uscr;", 
+            "description": "Named entity: Uscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Utilde", 
+            "description": "Bad named entity: Utilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Utilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Utilde;", 
+            "description": "Named entity: Utilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0168"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uuml", 
+            "description": "Named entity: Uuml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Uuml;", 
+            "description": "Named entity: Uuml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VDash", 
+            "description": "Bad named entity: VDash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&VDash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VDash;", 
+            "description": "Named entity: VDash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vbar", 
+            "description": "Bad named entity: Vbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vbar;", 
+            "description": "Named entity: Vbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aeb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vcy", 
+            "description": "Bad named entity: Vcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vcy;", 
+            "description": "Named entity: Vcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0412"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vdash", 
+            "description": "Bad named entity: Vdash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vdash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vdash;", 
+            "description": "Named entity: Vdash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vdashl", 
+            "description": "Bad named entity: Vdashl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vdashl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vdashl;", 
+            "description": "Named entity: Vdashl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ae6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vee", 
+            "description": "Bad named entity: Vee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vee;", 
+            "description": "Named entity: Vee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Verbar", 
+            "description": "Bad named entity: Verbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Verbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Verbar;", 
+            "description": "Named entity: Verbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2016"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vert", 
+            "description": "Bad named entity: Vert without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vert"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vert;", 
+            "description": "Named entity: Vert; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2016"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalBar", 
+            "description": "Bad named entity: VerticalBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&VerticalBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalBar;", 
+            "description": "Named entity: VerticalBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2223"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalLine", 
+            "description": "Bad named entity: VerticalLine without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&VerticalLine"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalLine;", 
+            "description": "Named entity: VerticalLine; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "|"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalSeparator", 
+            "description": "Bad named entity: VerticalSeparator without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&VerticalSeparator"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalSeparator;", 
+            "description": "Named entity: VerticalSeparator; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2758"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalTilde", 
+            "description": "Bad named entity: VerticalTilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&VerticalTilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VerticalTilde;", 
+            "description": "Named entity: VerticalTilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2240"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VeryThinSpace", 
+            "description": "Bad named entity: VeryThinSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&VeryThinSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&VeryThinSpace;", 
+            "description": "Named entity: VeryThinSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vfr", 
+            "description": "Bad named entity: Vfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vfr;", 
+            "description": "Named entity: Vfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd19"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vopf", 
+            "description": "Bad named entity: Vopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vopf;", 
+            "description": "Named entity: Vopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd4d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vscr", 
+            "description": "Bad named entity: Vscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vscr;", 
+            "description": "Named entity: Vscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vvdash", 
+            "description": "Bad named entity: Vvdash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Vvdash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Vvdash;", 
+            "description": "Named entity: Vvdash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wcirc", 
+            "description": "Bad named entity: Wcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Wcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wcirc;", 
+            "description": "Named entity: Wcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0174"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wedge", 
+            "description": "Bad named entity: Wedge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Wedge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wedge;", 
+            "description": "Named entity: Wedge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wfr", 
+            "description": "Bad named entity: Wfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Wfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wfr;", 
+            "description": "Named entity: Wfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd1a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wopf", 
+            "description": "Bad named entity: Wopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Wopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wopf;", 
+            "description": "Named entity: Wopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd4e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wscr", 
+            "description": "Bad named entity: Wscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Wscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Wscr;", 
+            "description": "Named entity: Wscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xfr", 
+            "description": "Bad named entity: Xfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Xfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xfr;", 
+            "description": "Named entity: Xfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd1b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xi", 
+            "description": "Bad named entity: Xi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Xi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xi;", 
+            "description": "Named entity: Xi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u039e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xopf", 
+            "description": "Bad named entity: Xopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Xopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xopf;", 
+            "description": "Named entity: Xopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd4f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xscr", 
+            "description": "Bad named entity: Xscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Xscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Xscr;", 
+            "description": "Named entity: Xscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&YAcy", 
+            "description": "Bad named entity: YAcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&YAcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&YAcy;", 
+            "description": "Named entity: YAcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u042f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&YIcy", 
+            "description": "Bad named entity: YIcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&YIcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&YIcy;", 
+            "description": "Named entity: YIcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0407"
+                ]
+            ]
+        }, 
+        {
+            "input": "&YUcy", 
+            "description": "Bad named entity: YUcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&YUcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&YUcy;", 
+            "description": "Named entity: YUcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u042e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yacute", 
+            "description": "Named entity: Yacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yacute;", 
+            "description": "Named entity: Yacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ycirc", 
+            "description": "Bad named entity: Ycirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ycirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ycirc;", 
+            "description": "Named entity: Ycirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0176"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ycy", 
+            "description": "Bad named entity: Ycy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Ycy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Ycy;", 
+            "description": "Named entity: Ycy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u042b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yfr", 
+            "description": "Bad named entity: Yfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Yfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yfr;", 
+            "description": "Named entity: Yfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd1c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yopf", 
+            "description": "Bad named entity: Yopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Yopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yopf;", 
+            "description": "Named entity: Yopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd50"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yscr", 
+            "description": "Bad named entity: Yscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Yscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yscr;", 
+            "description": "Named entity: Yscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yuml", 
+            "description": "Bad named entity: Yuml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Yuml"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Yuml;", 
+            "description": "Named entity: Yuml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0178"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ZHcy", 
+            "description": "Bad named entity: ZHcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ZHcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ZHcy;", 
+            "description": "Named entity: ZHcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0416"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zacute", 
+            "description": "Bad named entity: Zacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zacute;", 
+            "description": "Named entity: Zacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0179"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zcaron", 
+            "description": "Bad named entity: Zcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zcaron;", 
+            "description": "Named entity: Zcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u017d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zcy", 
+            "description": "Bad named entity: Zcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zcy;", 
+            "description": "Named entity: Zcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0417"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zdot", 
+            "description": "Bad named entity: Zdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zdot;", 
+            "description": "Named entity: Zdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u017b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ZeroWidthSpace", 
+            "description": "Bad named entity: ZeroWidthSpace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ZeroWidthSpace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ZeroWidthSpace;", 
+            "description": "Named entity: ZeroWidthSpace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zeta", 
+            "description": "Bad named entity: Zeta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zeta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zeta;", 
+            "description": "Named entity: Zeta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0396"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zfr", 
+            "description": "Bad named entity: Zfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zfr;", 
+            "description": "Named entity: Zfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2128"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zopf", 
+            "description": "Bad named entity: Zopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zopf;", 
+            "description": "Named entity: Zopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2124"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zscr", 
+            "description": "Bad named entity: Zscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&Zscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&Zscr;", 
+            "description": "Named entity: Zscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aacute", 
+            "description": "Named entity: aacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aacute;", 
+            "description": "Named entity: aacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&abreve", 
+            "description": "Bad named entity: abreve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&abreve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&abreve;", 
+            "description": "Named entity: abreve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0103"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ac", 
+            "description": "Bad named entity: ac without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ac;", 
+            "description": "Named entity: ac; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acE", 
+            "description": "Bad named entity: acE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&acE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acE;", 
+            "description": "Named entity: acE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223e\u0333"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acd", 
+            "description": "Bad named entity: acd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&acd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acd;", 
+            "description": "Named entity: acd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acirc", 
+            "description": "Named entity: acirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acirc;", 
+            "description": "Named entity: acirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acute", 
+            "description": "Named entity: acute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acute;", 
+            "description": "Named entity: acute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acy", 
+            "description": "Bad named entity: acy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&acy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&acy;", 
+            "description": "Named entity: acy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0430"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aelig", 
+            "description": "Named entity: aelig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aelig;", 
+            "description": "Named entity: aelig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&af", 
+            "description": "Bad named entity: af without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&af"
+                ]
+            ]
+        }, 
+        {
+            "input": "&af;", 
+            "description": "Named entity: af; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2061"
+                ]
+            ]
+        }, 
+        {
+            "input": "&afr", 
+            "description": "Bad named entity: afr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&afr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&afr;", 
+            "description": "Named entity: afr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd1e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&agrave", 
+            "description": "Named entity: agrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&agrave;", 
+            "description": "Named entity: agrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&alefsym", 
+            "description": "Bad named entity: alefsym without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&alefsym"
+                ]
+            ]
+        }, 
+        {
+            "input": "&alefsym;", 
+            "description": "Named entity: alefsym; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2135"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aleph", 
+            "description": "Bad named entity: aleph without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&aleph"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aleph;", 
+            "description": "Named entity: aleph; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2135"
+                ]
+            ]
+        }, 
+        {
+            "input": "&alpha", 
+            "description": "Bad named entity: alpha without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&alpha"
+                ]
+            ]
+        }, 
+        {
+            "input": "&alpha;", 
+            "description": "Named entity: alpha; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&amacr", 
+            "description": "Bad named entity: amacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&amacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&amacr;", 
+            "description": "Named entity: amacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0101"
+                ]
+            ]
+        }, 
+        {
+            "input": "&amalg", 
+            "description": "Bad named entity: amalg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&amalg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&amalg;", 
+            "description": "Named entity: amalg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a3f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&amp", 
+            "description": "Named entity: amp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&"
+                ]
+            ]
+        }, 
+        {
+            "input": "&amp;", 
+            "description": "Named entity: amp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "&"
+                ]
+            ]
+        }, 
+        {
+            "input": "&and", 
+            "description": "Bad named entity: and without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&and"
+                ]
+            ]
+        }, 
+        {
+            "input": "&and;", 
+            "description": "Named entity: and; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2227"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andand", 
+            "description": "Bad named entity: andand without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&andand"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andand;", 
+            "description": "Named entity: andand; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a55"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andd", 
+            "description": "Bad named entity: andd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&andd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andd;", 
+            "description": "Named entity: andd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a5c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andslope", 
+            "description": "Bad named entity: andslope without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&andslope"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andslope;", 
+            "description": "Named entity: andslope; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a58"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andv", 
+            "description": "Bad named entity: andv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&andv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&andv;", 
+            "description": "Named entity: andv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a5a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ang", 
+            "description": "Bad named entity: ang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ang;", 
+            "description": "Named entity: ang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2220"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ange", 
+            "description": "Bad named entity: ange without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ange"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ange;", 
+            "description": "Named entity: ange; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angle", 
+            "description": "Bad named entity: angle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angle;", 
+            "description": "Named entity: angle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2220"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsd", 
+            "description": "Bad named entity: angmsd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsd;", 
+            "description": "Named entity: angmsd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2221"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdaa", 
+            "description": "Bad named entity: angmsdaa without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdaa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdaa;", 
+            "description": "Named entity: angmsdaa; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdab", 
+            "description": "Bad named entity: angmsdab without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdab;", 
+            "description": "Named entity: angmsdab; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdac", 
+            "description": "Bad named entity: angmsdac without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdac;", 
+            "description": "Named entity: angmsdac; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdad", 
+            "description": "Bad named entity: angmsdad without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdad;", 
+            "description": "Named entity: angmsdad; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29ab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdae", 
+            "description": "Bad named entity: angmsdae without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdae;", 
+            "description": "Named entity: angmsdae; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdaf", 
+            "description": "Bad named entity: angmsdaf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdaf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdaf;", 
+            "description": "Named entity: angmsdaf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29ad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdag", 
+            "description": "Bad named entity: angmsdag without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdag"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdag;", 
+            "description": "Named entity: angmsdag; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdah", 
+            "description": "Bad named entity: angmsdah without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angmsdah"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angmsdah;", 
+            "description": "Named entity: angmsdah; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29af"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angrt", 
+            "description": "Bad named entity: angrt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angrt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angrt;", 
+            "description": "Named entity: angrt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angrtvb", 
+            "description": "Bad named entity: angrtvb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angrtvb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angrtvb;", 
+            "description": "Named entity: angrtvb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angrtvbd", 
+            "description": "Bad named entity: angrtvbd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angrtvbd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angrtvbd;", 
+            "description": "Named entity: angrtvbd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u299d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angsph", 
+            "description": "Bad named entity: angsph without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angsph"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angsph;", 
+            "description": "Named entity: angsph; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2222"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angst", 
+            "description": "Bad named entity: angst without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angst"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angst;", 
+            "description": "Named entity: angst; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angzarr", 
+            "description": "Bad named entity: angzarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&angzarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&angzarr;", 
+            "description": "Named entity: angzarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u237c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aogon", 
+            "description": "Bad named entity: aogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&aogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aogon;", 
+            "description": "Named entity: aogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0105"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aopf", 
+            "description": "Bad named entity: aopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&aopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aopf;", 
+            "description": "Named entity: aopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd52"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ap", 
+            "description": "Bad named entity: ap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ap;", 
+            "description": "Named entity: ap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2248"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apE", 
+            "description": "Bad named entity: apE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&apE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apE;", 
+            "description": "Named entity: apE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a70"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apacir", 
+            "description": "Bad named entity: apacir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&apacir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apacir;", 
+            "description": "Named entity: apacir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a6f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ape", 
+            "description": "Bad named entity: ape without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ape"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ape;", 
+            "description": "Named entity: ape; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apid", 
+            "description": "Bad named entity: apid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&apid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apid;", 
+            "description": "Named entity: apid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apos", 
+            "description": "Bad named entity: apos without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&apos"
+                ]
+            ]
+        }, 
+        {
+            "input": "&apos;", 
+            "description": "Named entity: apos; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "'"
+                ]
+            ]
+        }, 
+        {
+            "input": "&approx", 
+            "description": "Bad named entity: approx without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&approx"
+                ]
+            ]
+        }, 
+        {
+            "input": "&approx;", 
+            "description": "Named entity: approx; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2248"
+                ]
+            ]
+        }, 
+        {
+            "input": "&approxeq", 
+            "description": "Bad named entity: approxeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&approxeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&approxeq;", 
+            "description": "Named entity: approxeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aring", 
+            "description": "Named entity: aring without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&aring;", 
+            "description": "Named entity: aring; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ascr", 
+            "description": "Bad named entity: ascr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ascr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ascr;", 
+            "description": "Named entity: ascr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ast", 
+            "description": "Bad named entity: ast without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ast"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ast;", 
+            "description": "Named entity: ast; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "*"
+                ]
+            ]
+        }, 
+        {
+            "input": "&asymp", 
+            "description": "Bad named entity: asymp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&asymp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&asymp;", 
+            "description": "Named entity: asymp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2248"
+                ]
+            ]
+        }, 
+        {
+            "input": "&asympeq", 
+            "description": "Bad named entity: asympeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&asympeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&asympeq;", 
+            "description": "Named entity: asympeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&atilde", 
+            "description": "Named entity: atilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&atilde;", 
+            "description": "Named entity: atilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&auml", 
+            "description": "Named entity: auml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&auml;", 
+            "description": "Named entity: auml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&awconint", 
+            "description": "Bad named entity: awconint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&awconint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&awconint;", 
+            "description": "Named entity: awconint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2233"
+                ]
+            ]
+        }, 
+        {
+            "input": "&awint", 
+            "description": "Bad named entity: awint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&awint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&awint;", 
+            "description": "Named entity: awint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a11"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bNot", 
+            "description": "Bad named entity: bNot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bNot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bNot;", 
+            "description": "Named entity: bNot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backcong", 
+            "description": "Bad named entity: backcong without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&backcong"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backcong;", 
+            "description": "Named entity: backcong; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backepsilon", 
+            "description": "Bad named entity: backepsilon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&backepsilon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backepsilon;", 
+            "description": "Named entity: backepsilon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backprime", 
+            "description": "Bad named entity: backprime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&backprime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backprime;", 
+            "description": "Named entity: backprime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2035"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backsim", 
+            "description": "Bad named entity: backsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&backsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backsim;", 
+            "description": "Named entity: backsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backsimeq", 
+            "description": "Bad named entity: backsimeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&backsimeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&backsimeq;", 
+            "description": "Named entity: backsimeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&barvee", 
+            "description": "Bad named entity: barvee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&barvee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&barvee;", 
+            "description": "Named entity: barvee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&barwed", 
+            "description": "Bad named entity: barwed without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&barwed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&barwed;", 
+            "description": "Named entity: barwed; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2305"
+                ]
+            ]
+        }, 
+        {
+            "input": "&barwedge", 
+            "description": "Bad named entity: barwedge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&barwedge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&barwedge;", 
+            "description": "Named entity: barwedge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2305"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bbrk", 
+            "description": "Bad named entity: bbrk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bbrk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bbrk;", 
+            "description": "Named entity: bbrk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bbrktbrk", 
+            "description": "Bad named entity: bbrktbrk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bbrktbrk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bbrktbrk;", 
+            "description": "Named entity: bbrktbrk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bcong", 
+            "description": "Bad named entity: bcong without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bcong"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bcong;", 
+            "description": "Named entity: bcong; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bcy", 
+            "description": "Bad named entity: bcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bcy;", 
+            "description": "Named entity: bcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0431"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bdquo", 
+            "description": "Bad named entity: bdquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bdquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bdquo;", 
+            "description": "Named entity: bdquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&becaus", 
+            "description": "Bad named entity: becaus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&becaus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&becaus;", 
+            "description": "Named entity: becaus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2235"
+                ]
+            ]
+        }, 
+        {
+            "input": "&because", 
+            "description": "Bad named entity: because without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&because"
+                ]
+            ]
+        }, 
+        {
+            "input": "&because;", 
+            "description": "Named entity: because; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2235"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bemptyv", 
+            "description": "Bad named entity: bemptyv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bemptyv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bemptyv;", 
+            "description": "Named entity: bemptyv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bepsi", 
+            "description": "Bad named entity: bepsi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bepsi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bepsi;", 
+            "description": "Named entity: bepsi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bernou", 
+            "description": "Bad named entity: bernou without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bernou"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bernou;", 
+            "description": "Named entity: bernou; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u212c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&beta", 
+            "description": "Bad named entity: beta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&beta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&beta;", 
+            "description": "Named entity: beta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&beth", 
+            "description": "Bad named entity: beth without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&beth"
+                ]
+            ]
+        }, 
+        {
+            "input": "&beth;", 
+            "description": "Named entity: beth; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2136"
+                ]
+            ]
+        }, 
+        {
+            "input": "&between", 
+            "description": "Bad named entity: between without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&between"
+                ]
+            ]
+        }, 
+        {
+            "input": "&between;", 
+            "description": "Named entity: between; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bfr", 
+            "description": "Bad named entity: bfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bfr;", 
+            "description": "Named entity: bfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd1f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigcap", 
+            "description": "Bad named entity: bigcap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigcap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigcap;", 
+            "description": "Named entity: bigcap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigcirc", 
+            "description": "Bad named entity: bigcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigcirc;", 
+            "description": "Named entity: bigcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ef"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigcup", 
+            "description": "Bad named entity: bigcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigcup;", 
+            "description": "Named entity: bigcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigodot", 
+            "description": "Bad named entity: bigodot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigodot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigodot;", 
+            "description": "Named entity: bigodot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigoplus", 
+            "description": "Bad named entity: bigoplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigoplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigoplus;", 
+            "description": "Named entity: bigoplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a01"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigotimes", 
+            "description": "Bad named entity: bigotimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigotimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigotimes;", 
+            "description": "Named entity: bigotimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a02"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigsqcup", 
+            "description": "Bad named entity: bigsqcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigsqcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigsqcup;", 
+            "description": "Named entity: bigsqcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a06"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigstar", 
+            "description": "Bad named entity: bigstar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigstar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigstar;", 
+            "description": "Named entity: bigstar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2605"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigtriangledown", 
+            "description": "Bad named entity: bigtriangledown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigtriangledown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigtriangledown;", 
+            "description": "Named entity: bigtriangledown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigtriangleup", 
+            "description": "Bad named entity: bigtriangleup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigtriangleup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigtriangleup;", 
+            "description": "Named entity: bigtriangleup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&biguplus", 
+            "description": "Bad named entity: biguplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&biguplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&biguplus;", 
+            "description": "Named entity: biguplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a04"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigvee", 
+            "description": "Bad named entity: bigvee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigvee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigvee;", 
+            "description": "Named entity: bigvee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigwedge", 
+            "description": "Bad named entity: bigwedge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bigwedge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bigwedge;", 
+            "description": "Named entity: bigwedge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bkarow", 
+            "description": "Bad named entity: bkarow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bkarow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bkarow;", 
+            "description": "Named entity: bkarow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u290d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacklozenge", 
+            "description": "Bad named entity: blacklozenge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blacklozenge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacklozenge;", 
+            "description": "Named entity: blacklozenge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacksquare", 
+            "description": "Bad named entity: blacksquare without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blacksquare"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacksquare;", 
+            "description": "Named entity: blacksquare; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangle", 
+            "description": "Bad named entity: blacktriangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blacktriangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangle;", 
+            "description": "Named entity: blacktriangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangledown", 
+            "description": "Bad named entity: blacktriangledown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blacktriangledown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangledown;", 
+            "description": "Named entity: blacktriangledown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangleleft", 
+            "description": "Bad named entity: blacktriangleleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blacktriangleleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangleleft;", 
+            "description": "Named entity: blacktriangleleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangleright", 
+            "description": "Bad named entity: blacktriangleright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blacktriangleright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blacktriangleright;", 
+            "description": "Named entity: blacktriangleright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blank", 
+            "description": "Bad named entity: blank without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blank"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blank;", 
+            "description": "Named entity: blank; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2423"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blk12", 
+            "description": "Bad named entity: blk12 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blk12"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blk12;", 
+            "description": "Named entity: blk12; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2592"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blk14", 
+            "description": "Bad named entity: blk14 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blk14"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blk14;", 
+            "description": "Named entity: blk14; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2591"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blk34", 
+            "description": "Bad named entity: blk34 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&blk34"
+                ]
+            ]
+        }, 
+        {
+            "input": "&blk34;", 
+            "description": "Named entity: blk34; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2593"
+                ]
+            ]
+        }, 
+        {
+            "input": "&block", 
+            "description": "Bad named entity: block without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&block"
+                ]
+            ]
+        }, 
+        {
+            "input": "&block;", 
+            "description": "Named entity: block; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2588"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bne", 
+            "description": "Bad named entity: bne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bne;", 
+            "description": "Named entity: bne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "=\u20e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bnequiv", 
+            "description": "Bad named entity: bnequiv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bnequiv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bnequiv;", 
+            "description": "Named entity: bnequiv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2261\u20e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bnot", 
+            "description": "Bad named entity: bnot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bnot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bnot;", 
+            "description": "Named entity: bnot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2310"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bopf", 
+            "description": "Bad named entity: bopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bopf;", 
+            "description": "Named entity: bopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd53"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bot", 
+            "description": "Bad named entity: bot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bot;", 
+            "description": "Named entity: bot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bottom", 
+            "description": "Bad named entity: bottom without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bottom"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bottom;", 
+            "description": "Named entity: bottom; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bowtie", 
+            "description": "Bad named entity: bowtie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bowtie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bowtie;", 
+            "description": "Named entity: bowtie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDL", 
+            "description": "Bad named entity: boxDL without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxDL"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDL;", 
+            "description": "Named entity: boxDL; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2557"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDR", 
+            "description": "Bad named entity: boxDR without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxDR"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDR;", 
+            "description": "Named entity: boxDR; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2554"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDl", 
+            "description": "Bad named entity: boxDl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxDl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDl;", 
+            "description": "Named entity: boxDl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2556"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDr", 
+            "description": "Bad named entity: boxDr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxDr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxDr;", 
+            "description": "Named entity: boxDr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2553"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxH", 
+            "description": "Bad named entity: boxH without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxH"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxH;", 
+            "description": "Named entity: boxH; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2550"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHD", 
+            "description": "Bad named entity: boxHD without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxHD"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHD;", 
+            "description": "Named entity: boxHD; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2566"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHU", 
+            "description": "Bad named entity: boxHU without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxHU"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHU;", 
+            "description": "Named entity: boxHU; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2569"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHd", 
+            "description": "Bad named entity: boxHd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxHd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHd;", 
+            "description": "Named entity: boxHd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2564"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHu", 
+            "description": "Bad named entity: boxHu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxHu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxHu;", 
+            "description": "Named entity: boxHu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2567"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUL", 
+            "description": "Bad named entity: boxUL without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxUL"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUL;", 
+            "description": "Named entity: boxUL; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u255d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUR", 
+            "description": "Bad named entity: boxUR without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxUR"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUR;", 
+            "description": "Named entity: boxUR; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u255a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUl", 
+            "description": "Bad named entity: boxUl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxUl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUl;", 
+            "description": "Named entity: boxUl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u255c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUr", 
+            "description": "Bad named entity: boxUr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxUr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxUr;", 
+            "description": "Named entity: boxUr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2559"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxV", 
+            "description": "Bad named entity: boxV without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxV"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxV;", 
+            "description": "Named entity: boxV; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2551"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVH", 
+            "description": "Bad named entity: boxVH without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxVH"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVH;", 
+            "description": "Named entity: boxVH; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u256c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVL", 
+            "description": "Bad named entity: boxVL without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxVL"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVL;", 
+            "description": "Named entity: boxVL; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2563"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVR", 
+            "description": "Bad named entity: boxVR without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxVR"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVR;", 
+            "description": "Named entity: boxVR; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2560"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVh", 
+            "description": "Bad named entity: boxVh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxVh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVh;", 
+            "description": "Named entity: boxVh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u256b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVl", 
+            "description": "Bad named entity: boxVl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxVl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVl;", 
+            "description": "Named entity: boxVl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2562"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVr", 
+            "description": "Bad named entity: boxVr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxVr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxVr;", 
+            "description": "Named entity: boxVr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u255f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxbox", 
+            "description": "Bad named entity: boxbox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxbox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxbox;", 
+            "description": "Named entity: boxbox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdL", 
+            "description": "Bad named entity: boxdL without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxdL"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdL;", 
+            "description": "Named entity: boxdL; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2555"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdR", 
+            "description": "Bad named entity: boxdR without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxdR"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdR;", 
+            "description": "Named entity: boxdR; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2552"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdl", 
+            "description": "Bad named entity: boxdl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxdl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdl;", 
+            "description": "Named entity: boxdl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2510"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdr", 
+            "description": "Bad named entity: boxdr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxdr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxdr;", 
+            "description": "Named entity: boxdr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u250c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxh", 
+            "description": "Bad named entity: boxh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxh;", 
+            "description": "Named entity: boxh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2500"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhD", 
+            "description": "Bad named entity: boxhD without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxhD"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhD;", 
+            "description": "Named entity: boxhD; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2565"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhU", 
+            "description": "Bad named entity: boxhU without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxhU"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhU;", 
+            "description": "Named entity: boxhU; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2568"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhd", 
+            "description": "Bad named entity: boxhd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxhd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhd;", 
+            "description": "Named entity: boxhd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u252c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhu", 
+            "description": "Bad named entity: boxhu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxhu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxhu;", 
+            "description": "Named entity: boxhu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2534"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxminus", 
+            "description": "Bad named entity: boxminus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxminus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxminus;", 
+            "description": "Named entity: boxminus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxplus", 
+            "description": "Bad named entity: boxplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxplus;", 
+            "description": "Named entity: boxplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxtimes", 
+            "description": "Bad named entity: boxtimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxtimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxtimes;", 
+            "description": "Named entity: boxtimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxuL", 
+            "description": "Bad named entity: boxuL without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxuL"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxuL;", 
+            "description": "Named entity: boxuL; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u255b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxuR", 
+            "description": "Bad named entity: boxuR without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxuR"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxuR;", 
+            "description": "Named entity: boxuR; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2558"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxul", 
+            "description": "Bad named entity: boxul without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxul"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxul;", 
+            "description": "Named entity: boxul; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2518"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxur", 
+            "description": "Bad named entity: boxur without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxur"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxur;", 
+            "description": "Named entity: boxur; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2514"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxv", 
+            "description": "Bad named entity: boxv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxv;", 
+            "description": "Named entity: boxv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2502"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvH", 
+            "description": "Bad named entity: boxvH without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxvH"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvH;", 
+            "description": "Named entity: boxvH; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u256a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvL", 
+            "description": "Bad named entity: boxvL without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxvL"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvL;", 
+            "description": "Named entity: boxvL; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2561"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvR", 
+            "description": "Bad named entity: boxvR without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxvR"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvR;", 
+            "description": "Named entity: boxvR; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u255e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvh", 
+            "description": "Bad named entity: boxvh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxvh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvh;", 
+            "description": "Named entity: boxvh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u253c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvl", 
+            "description": "Bad named entity: boxvl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxvl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvl;", 
+            "description": "Named entity: boxvl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2524"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvr", 
+            "description": "Bad named entity: boxvr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&boxvr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&boxvr;", 
+            "description": "Named entity: boxvr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u251c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bprime", 
+            "description": "Bad named entity: bprime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bprime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bprime;", 
+            "description": "Named entity: bprime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2035"
+                ]
+            ]
+        }, 
+        {
+            "input": "&breve", 
+            "description": "Bad named entity: breve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&breve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&breve;", 
+            "description": "Named entity: breve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02d8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&brvbar", 
+            "description": "Named entity: brvbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&brvbar;", 
+            "description": "Named entity: brvbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bscr", 
+            "description": "Bad named entity: bscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bscr;", 
+            "description": "Named entity: bscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsemi", 
+            "description": "Bad named entity: bsemi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bsemi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsemi;", 
+            "description": "Named entity: bsemi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u204f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsim", 
+            "description": "Bad named entity: bsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsim;", 
+            "description": "Named entity: bsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsime", 
+            "description": "Bad named entity: bsime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bsime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsime;", 
+            "description": "Named entity: bsime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsol", 
+            "description": "Bad named entity: bsol without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bsol"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsol;", 
+            "description": "Named entity: bsol; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\\"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsolb", 
+            "description": "Bad named entity: bsolb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bsolb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsolb;", 
+            "description": "Named entity: bsolb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsolhsub", 
+            "description": "Bad named entity: bsolhsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bsolhsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bsolhsub;", 
+            "description": "Named entity: bsolhsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bull", 
+            "description": "Bad named entity: bull without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bull"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bull;", 
+            "description": "Named entity: bull; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2022"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bullet", 
+            "description": "Bad named entity: bullet without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bullet"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bullet;", 
+            "description": "Named entity: bullet; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2022"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bump", 
+            "description": "Bad named entity: bump without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bump"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bump;", 
+            "description": "Named entity: bump; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bumpE", 
+            "description": "Bad named entity: bumpE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bumpE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bumpE;", 
+            "description": "Named entity: bumpE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bumpe", 
+            "description": "Bad named entity: bumpe without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bumpe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bumpe;", 
+            "description": "Named entity: bumpe; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bumpeq", 
+            "description": "Bad named entity: bumpeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&bumpeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&bumpeq;", 
+            "description": "Named entity: bumpeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cacute", 
+            "description": "Bad named entity: cacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cacute;", 
+            "description": "Named entity: cacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0107"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cap", 
+            "description": "Bad named entity: cap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cap;", 
+            "description": "Named entity: cap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2229"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capand", 
+            "description": "Bad named entity: capand without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&capand"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capand;", 
+            "description": "Named entity: capand; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a44"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capbrcup", 
+            "description": "Bad named entity: capbrcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&capbrcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capbrcup;", 
+            "description": "Named entity: capbrcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a49"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capcap", 
+            "description": "Bad named entity: capcap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&capcap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capcap;", 
+            "description": "Named entity: capcap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a4b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capcup", 
+            "description": "Bad named entity: capcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&capcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capcup;", 
+            "description": "Named entity: capcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a47"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capdot", 
+            "description": "Bad named entity: capdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&capdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&capdot;", 
+            "description": "Named entity: capdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a40"
+                ]
+            ]
+        }, 
+        {
+            "input": "&caps", 
+            "description": "Bad named entity: caps without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&caps"
+                ]
+            ]
+        }, 
+        {
+            "input": "&caps;", 
+            "description": "Named entity: caps; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2229\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&caret", 
+            "description": "Bad named entity: caret without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&caret"
+                ]
+            ]
+        }, 
+        {
+            "input": "&caret;", 
+            "description": "Named entity: caret; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2041"
+                ]
+            ]
+        }, 
+        {
+            "input": "&caron", 
+            "description": "Bad named entity: caron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&caron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&caron;", 
+            "description": "Named entity: caron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccaps", 
+            "description": "Bad named entity: ccaps without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ccaps"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccaps;", 
+            "description": "Named entity: ccaps; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a4d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccaron", 
+            "description": "Bad named entity: ccaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ccaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccaron;", 
+            "description": "Named entity: ccaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u010d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccedil", 
+            "description": "Named entity: ccedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccedil;", 
+            "description": "Named entity: ccedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccirc", 
+            "description": "Bad named entity: ccirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ccirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccirc;", 
+            "description": "Named entity: ccirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0109"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccups", 
+            "description": "Bad named entity: ccups without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ccups"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccups;", 
+            "description": "Named entity: ccups; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a4c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccupssm", 
+            "description": "Bad named entity: ccupssm without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ccupssm"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ccupssm;", 
+            "description": "Named entity: ccupssm; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a50"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cdot", 
+            "description": "Bad named entity: cdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cdot;", 
+            "description": "Named entity: cdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u010b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cedil", 
+            "description": "Named entity: cedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cedil;", 
+            "description": "Named entity: cedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cemptyv", 
+            "description": "Bad named entity: cemptyv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cemptyv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cemptyv;", 
+            "description": "Named entity: cemptyv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cent", 
+            "description": "Named entity: cent without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cent;", 
+            "description": "Named entity: cent; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&centerdot;", 
+            "description": "Named entity: centerdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cfr", 
+            "description": "Bad named entity: cfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cfr;", 
+            "description": "Named entity: cfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd20"
+                ]
+            ]
+        }, 
+        {
+            "input": "&chcy", 
+            "description": "Bad named entity: chcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&chcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&chcy;", 
+            "description": "Named entity: chcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0447"
+                ]
+            ]
+        }, 
+        {
+            "input": "&check", 
+            "description": "Bad named entity: check without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&check"
+                ]
+            ]
+        }, 
+        {
+            "input": "&check;", 
+            "description": "Named entity: check; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2713"
+                ]
+            ]
+        }, 
+        {
+            "input": "&checkmark", 
+            "description": "Bad named entity: checkmark without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&checkmark"
+                ]
+            ]
+        }, 
+        {
+            "input": "&checkmark;", 
+            "description": "Named entity: checkmark; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2713"
+                ]
+            ]
+        }, 
+        {
+            "input": "&chi", 
+            "description": "Bad named entity: chi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&chi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&chi;", 
+            "description": "Named entity: chi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cir", 
+            "description": "Bad named entity: cir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cir;", 
+            "description": "Named entity: cir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirE", 
+            "description": "Bad named entity: cirE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cirE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirE;", 
+            "description": "Named entity: cirE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circ", 
+            "description": "Bad named entity: circ without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circ"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circ;", 
+            "description": "Named entity: circ; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circeq", 
+            "description": "Bad named entity: circeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circeq;", 
+            "description": "Named entity: circeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2257"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circlearrowleft", 
+            "description": "Bad named entity: circlearrowleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circlearrowleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circlearrowleft;", 
+            "description": "Named entity: circlearrowleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circlearrowright", 
+            "description": "Bad named entity: circlearrowright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circlearrowright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circlearrowright;", 
+            "description": "Named entity: circlearrowright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledR", 
+            "description": "Bad named entity: circledR without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circledR"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledR;", 
+            "description": "Named entity: circledR; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledS", 
+            "description": "Bad named entity: circledS without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circledS"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledS;", 
+            "description": "Named entity: circledS; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u24c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledast", 
+            "description": "Bad named entity: circledast without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circledast"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledast;", 
+            "description": "Named entity: circledast; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledcirc", 
+            "description": "Bad named entity: circledcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circledcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circledcirc;", 
+            "description": "Named entity: circledcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circleddash", 
+            "description": "Bad named entity: circleddash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&circleddash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&circleddash;", 
+            "description": "Named entity: circleddash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cire", 
+            "description": "Bad named entity: cire without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cire"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cire;", 
+            "description": "Named entity: cire; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2257"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirfnint", 
+            "description": "Bad named entity: cirfnint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cirfnint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirfnint;", 
+            "description": "Named entity: cirfnint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a10"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirmid", 
+            "description": "Bad named entity: cirmid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cirmid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirmid;", 
+            "description": "Named entity: cirmid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aef"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirscir", 
+            "description": "Bad named entity: cirscir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cirscir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cirscir;", 
+            "description": "Named entity: cirscir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&clubs", 
+            "description": "Bad named entity: clubs without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&clubs"
+                ]
+            ]
+        }, 
+        {
+            "input": "&clubs;", 
+            "description": "Named entity: clubs; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2663"
+                ]
+            ]
+        }, 
+        {
+            "input": "&clubsuit", 
+            "description": "Bad named entity: clubsuit without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&clubsuit"
+                ]
+            ]
+        }, 
+        {
+            "input": "&clubsuit;", 
+            "description": "Named entity: clubsuit; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2663"
+                ]
+            ]
+        }, 
+        {
+            "input": "&colon", 
+            "description": "Bad named entity: colon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&colon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&colon;", 
+            "description": "Named entity: colon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    ":"
+                ]
+            ]
+        }, 
+        {
+            "input": "&colone", 
+            "description": "Bad named entity: colone without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&colone"
+                ]
+            ]
+        }, 
+        {
+            "input": "&colone;", 
+            "description": "Named entity: colone; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2254"
+                ]
+            ]
+        }, 
+        {
+            "input": "&coloneq", 
+            "description": "Bad named entity: coloneq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&coloneq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&coloneq;", 
+            "description": "Named entity: coloneq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2254"
+                ]
+            ]
+        }, 
+        {
+            "input": "&comma", 
+            "description": "Bad named entity: comma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&comma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&comma;", 
+            "description": "Named entity: comma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    ","
+                ]
+            ]
+        }, 
+        {
+            "input": "&commat", 
+            "description": "Bad named entity: commat without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&commat"
+                ]
+            ]
+        }, 
+        {
+            "input": "&commat;", 
+            "description": "Named entity: commat; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "@"
+                ]
+            ]
+        }, 
+        {
+            "input": "&comp", 
+            "description": "Bad named entity: comp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&comp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&comp;", 
+            "description": "Named entity: comp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2201"
+                ]
+            ]
+        }, 
+        {
+            "input": "&compfn", 
+            "description": "Bad named entity: compfn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&compfn"
+                ]
+            ]
+        }, 
+        {
+            "input": "&compfn;", 
+            "description": "Named entity: compfn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2218"
+                ]
+            ]
+        }, 
+        {
+            "input": "&complement", 
+            "description": "Bad named entity: complement without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&complement"
+                ]
+            ]
+        }, 
+        {
+            "input": "&complement;", 
+            "description": "Named entity: complement; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2201"
+                ]
+            ]
+        }, 
+        {
+            "input": "&complexes", 
+            "description": "Bad named entity: complexes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&complexes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&complexes;", 
+            "description": "Named entity: complexes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2102"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cong", 
+            "description": "Bad named entity: cong without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cong"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cong;", 
+            "description": "Named entity: cong; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2245"
+                ]
+            ]
+        }, 
+        {
+            "input": "&congdot", 
+            "description": "Bad named entity: congdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&congdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&congdot;", 
+            "description": "Named entity: congdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a6d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&conint", 
+            "description": "Bad named entity: conint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&conint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&conint;", 
+            "description": "Named entity: conint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&copf", 
+            "description": "Bad named entity: copf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&copf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&copf;", 
+            "description": "Named entity: copf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd54"
+                ]
+            ]
+        }, 
+        {
+            "input": "&coprod", 
+            "description": "Bad named entity: coprod without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&coprod"
+                ]
+            ]
+        }, 
+        {
+            "input": "&coprod;", 
+            "description": "Named entity: coprod; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2210"
+                ]
+            ]
+        }, 
+        {
+            "input": "&copy", 
+            "description": "Named entity: copy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&copy;", 
+            "description": "Named entity: copy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&copysr;", 
+            "description": "Named entity: copysr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2117"
+                ]
+            ]
+        }, 
+        {
+            "input": "&crarr", 
+            "description": "Bad named entity: crarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&crarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&crarr;", 
+            "description": "Named entity: crarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cross", 
+            "description": "Bad named entity: cross without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cross"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cross;", 
+            "description": "Named entity: cross; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2717"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cscr", 
+            "description": "Bad named entity: cscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cscr;", 
+            "description": "Named entity: cscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csub", 
+            "description": "Bad named entity: csub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&csub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csub;", 
+            "description": "Named entity: csub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csube", 
+            "description": "Bad named entity: csube without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&csube"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csube;", 
+            "description": "Named entity: csube; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csup", 
+            "description": "Bad named entity: csup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&csup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csup;", 
+            "description": "Named entity: csup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csupe", 
+            "description": "Bad named entity: csupe without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&csupe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&csupe;", 
+            "description": "Named entity: csupe; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ctdot", 
+            "description": "Bad named entity: ctdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ctdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ctdot;", 
+            "description": "Named entity: ctdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ef"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cudarrl", 
+            "description": "Bad named entity: cudarrl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cudarrl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cudarrl;", 
+            "description": "Named entity: cudarrl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2938"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cudarrr", 
+            "description": "Bad named entity: cudarrr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cudarrr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cudarrr;", 
+            "description": "Named entity: cudarrr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2935"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuepr", 
+            "description": "Bad named entity: cuepr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cuepr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuepr;", 
+            "description": "Named entity: cuepr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22de"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuesc", 
+            "description": "Bad named entity: cuesc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cuesc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuesc;", 
+            "description": "Named entity: cuesc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22df"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cularr", 
+            "description": "Bad named entity: cularr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cularr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cularr;", 
+            "description": "Named entity: cularr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cularrp", 
+            "description": "Bad named entity: cularrp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cularrp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cularrp;", 
+            "description": "Named entity: cularrp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u293d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cup", 
+            "description": "Bad named entity: cup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cup;", 
+            "description": "Named entity: cup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupbrcap", 
+            "description": "Bad named entity: cupbrcap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cupbrcap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupbrcap;", 
+            "description": "Named entity: cupbrcap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a48"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupcap", 
+            "description": "Bad named entity: cupcap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cupcap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupcap;", 
+            "description": "Named entity: cupcap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a46"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupcup", 
+            "description": "Bad named entity: cupcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cupcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupcup;", 
+            "description": "Named entity: cupcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a4a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupdot", 
+            "description": "Bad named entity: cupdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cupdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupdot;", 
+            "description": "Named entity: cupdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupor", 
+            "description": "Bad named entity: cupor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cupor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cupor;", 
+            "description": "Named entity: cupor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a45"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cups", 
+            "description": "Bad named entity: cups without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cups"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cups;", 
+            "description": "Named entity: cups; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222a\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curarr", 
+            "description": "Bad named entity: curarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curarr;", 
+            "description": "Named entity: curarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curarrm", 
+            "description": "Bad named entity: curarrm without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curarrm"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curarrm;", 
+            "description": "Named entity: curarrm; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u293c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlyeqprec", 
+            "description": "Bad named entity: curlyeqprec without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curlyeqprec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlyeqprec;", 
+            "description": "Named entity: curlyeqprec; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22de"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlyeqsucc", 
+            "description": "Bad named entity: curlyeqsucc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curlyeqsucc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlyeqsucc;", 
+            "description": "Named entity: curlyeqsucc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22df"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlyvee", 
+            "description": "Bad named entity: curlyvee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curlyvee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlyvee;", 
+            "description": "Named entity: curlyvee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlywedge", 
+            "description": "Bad named entity: curlywedge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curlywedge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curlywedge;", 
+            "description": "Named entity: curlywedge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curren", 
+            "description": "Named entity: curren without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curren;", 
+            "description": "Named entity: curren; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curvearrowleft", 
+            "description": "Bad named entity: curvearrowleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curvearrowleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curvearrowleft;", 
+            "description": "Named entity: curvearrowleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curvearrowright", 
+            "description": "Bad named entity: curvearrowright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&curvearrowright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&curvearrowright;", 
+            "description": "Named entity: curvearrowright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuvee", 
+            "description": "Bad named entity: cuvee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cuvee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuvee;", 
+            "description": "Named entity: cuvee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuwed", 
+            "description": "Bad named entity: cuwed without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cuwed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cuwed;", 
+            "description": "Named entity: cuwed; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cwconint", 
+            "description": "Bad named entity: cwconint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cwconint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cwconint;", 
+            "description": "Named entity: cwconint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2232"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cwint", 
+            "description": "Bad named entity: cwint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cwint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cwint;", 
+            "description": "Named entity: cwint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2231"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cylcty", 
+            "description": "Bad named entity: cylcty without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&cylcty"
+                ]
+            ]
+        }, 
+        {
+            "input": "&cylcty;", 
+            "description": "Named entity: cylcty; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u232d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dArr", 
+            "description": "Bad named entity: dArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dArr;", 
+            "description": "Named entity: dArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dHar", 
+            "description": "Bad named entity: dHar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dHar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dHar;", 
+            "description": "Named entity: dHar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2965"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dagger", 
+            "description": "Bad named entity: dagger without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dagger"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dagger;", 
+            "description": "Named entity: dagger; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2020"
+                ]
+            ]
+        }, 
+        {
+            "input": "&daleth", 
+            "description": "Bad named entity: daleth without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&daleth"
+                ]
+            ]
+        }, 
+        {
+            "input": "&daleth;", 
+            "description": "Named entity: daleth; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2138"
+                ]
+            ]
+        }, 
+        {
+            "input": "&darr", 
+            "description": "Bad named entity: darr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&darr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&darr;", 
+            "description": "Named entity: darr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2193"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dash", 
+            "description": "Bad named entity: dash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dash;", 
+            "description": "Named entity: dash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2010"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dashv", 
+            "description": "Bad named entity: dashv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dashv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dashv;", 
+            "description": "Named entity: dashv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dbkarow", 
+            "description": "Bad named entity: dbkarow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dbkarow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dbkarow;", 
+            "description": "Named entity: dbkarow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u290f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dblac", 
+            "description": "Bad named entity: dblac without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dblac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dblac;", 
+            "description": "Named entity: dblac; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dcaron", 
+            "description": "Bad named entity: dcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dcaron;", 
+            "description": "Named entity: dcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u010f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dcy", 
+            "description": "Bad named entity: dcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dcy;", 
+            "description": "Named entity: dcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0434"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dd", 
+            "description": "Bad named entity: dd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dd;", 
+            "description": "Named entity: dd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2146"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ddagger", 
+            "description": "Bad named entity: ddagger without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ddagger"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ddagger;", 
+            "description": "Named entity: ddagger; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2021"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ddarr", 
+            "description": "Bad named entity: ddarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ddarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ddarr;", 
+            "description": "Named entity: ddarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ddotseq", 
+            "description": "Bad named entity: ddotseq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ddotseq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ddotseq;", 
+            "description": "Named entity: ddotseq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a77"
+                ]
+            ]
+        }, 
+        {
+            "input": "&deg", 
+            "description": "Named entity: deg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&deg;", 
+            "description": "Named entity: deg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&delta", 
+            "description": "Bad named entity: delta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&delta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&delta;", 
+            "description": "Named entity: delta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&demptyv", 
+            "description": "Bad named entity: demptyv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&demptyv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&demptyv;", 
+            "description": "Named entity: demptyv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dfisht", 
+            "description": "Bad named entity: dfisht without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dfisht"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dfisht;", 
+            "description": "Named entity: dfisht; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u297f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dfr", 
+            "description": "Bad named entity: dfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dfr;", 
+            "description": "Named entity: dfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd21"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dharl", 
+            "description": "Bad named entity: dharl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dharl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dharl;", 
+            "description": "Named entity: dharl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dharr", 
+            "description": "Bad named entity: dharr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dharr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dharr;", 
+            "description": "Named entity: dharr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diam", 
+            "description": "Bad named entity: diam without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&diam"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diam;", 
+            "description": "Named entity: diam; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diamond", 
+            "description": "Bad named entity: diamond without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&diamond"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diamond;", 
+            "description": "Named entity: diamond; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diamondsuit", 
+            "description": "Bad named entity: diamondsuit without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&diamondsuit"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diamondsuit;", 
+            "description": "Named entity: diamondsuit; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2666"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diams", 
+            "description": "Bad named entity: diams without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&diams"
+                ]
+            ]
+        }, 
+        {
+            "input": "&diams;", 
+            "description": "Named entity: diams; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2666"
+                ]
+            ]
+        }, 
+        {
+            "input": "&die", 
+            "description": "Bad named entity: die without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&die"
+                ]
+            ]
+        }, 
+        {
+            "input": "&die;", 
+            "description": "Named entity: die; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&digamma", 
+            "description": "Bad named entity: digamma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&digamma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&digamma;", 
+            "description": "Named entity: digamma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&disin", 
+            "description": "Bad named entity: disin without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&disin"
+                ]
+            ]
+        }, 
+        {
+            "input": "&disin;", 
+            "description": "Named entity: disin; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&div", 
+            "description": "Bad named entity: div without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&div"
+                ]
+            ]
+        }, 
+        {
+            "input": "&div;", 
+            "description": "Named entity: div; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&divide", 
+            "description": "Named entity: divide without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&divide;", 
+            "description": "Named entity: divide; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&divideontimes;", 
+            "description": "Named entity: divideontimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&divonx", 
+            "description": "Bad named entity: divonx without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&divonx"
+                ]
+            ]
+        }, 
+        {
+            "input": "&divonx;", 
+            "description": "Named entity: divonx; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&djcy", 
+            "description": "Bad named entity: djcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&djcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&djcy;", 
+            "description": "Named entity: djcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0452"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dlcorn", 
+            "description": "Bad named entity: dlcorn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dlcorn"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dlcorn;", 
+            "description": "Named entity: dlcorn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dlcrop", 
+            "description": "Bad named entity: dlcrop without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dlcrop"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dlcrop;", 
+            "description": "Named entity: dlcrop; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dollar", 
+            "description": "Bad named entity: dollar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dollar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dollar;", 
+            "description": "Named entity: dollar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "$"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dopf", 
+            "description": "Bad named entity: dopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dopf;", 
+            "description": "Named entity: dopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd55"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dot", 
+            "description": "Bad named entity: dot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dot;", 
+            "description": "Named entity: dot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02d9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&doteq", 
+            "description": "Bad named entity: doteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&doteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&doteq;", 
+            "description": "Named entity: doteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2250"
+                ]
+            ]
+        }, 
+        {
+            "input": "&doteqdot", 
+            "description": "Bad named entity: doteqdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&doteqdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&doteqdot;", 
+            "description": "Named entity: doteqdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2251"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dotminus", 
+            "description": "Bad named entity: dotminus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dotminus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dotminus;", 
+            "description": "Named entity: dotminus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2238"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dotplus", 
+            "description": "Bad named entity: dotplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dotplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dotplus;", 
+            "description": "Named entity: dotplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2214"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dotsquare", 
+            "description": "Bad named entity: dotsquare without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dotsquare"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dotsquare;", 
+            "description": "Named entity: dotsquare; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&doublebarwedge", 
+            "description": "Bad named entity: doublebarwedge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&doublebarwedge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&doublebarwedge;", 
+            "description": "Named entity: doublebarwedge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2306"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downarrow", 
+            "description": "Bad named entity: downarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&downarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downarrow;", 
+            "description": "Named entity: downarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2193"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downdownarrows", 
+            "description": "Bad named entity: downdownarrows without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&downdownarrows"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downdownarrows;", 
+            "description": "Named entity: downdownarrows; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downharpoonleft", 
+            "description": "Bad named entity: downharpoonleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&downharpoonleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downharpoonleft;", 
+            "description": "Named entity: downharpoonleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downharpoonright", 
+            "description": "Bad named entity: downharpoonright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&downharpoonright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&downharpoonright;", 
+            "description": "Named entity: downharpoonright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&drbkarow", 
+            "description": "Bad named entity: drbkarow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&drbkarow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&drbkarow;", 
+            "description": "Named entity: drbkarow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2910"
+                ]
+            ]
+        }, 
+        {
+            "input": "&drcorn", 
+            "description": "Bad named entity: drcorn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&drcorn"
+                ]
+            ]
+        }, 
+        {
+            "input": "&drcorn;", 
+            "description": "Named entity: drcorn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&drcrop", 
+            "description": "Bad named entity: drcrop without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&drcrop"
+                ]
+            ]
+        }, 
+        {
+            "input": "&drcrop;", 
+            "description": "Named entity: drcrop; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dscr", 
+            "description": "Bad named entity: dscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dscr;", 
+            "description": "Named entity: dscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcb9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dscy", 
+            "description": "Bad named entity: dscy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dscy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dscy;", 
+            "description": "Named entity: dscy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0455"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dsol", 
+            "description": "Bad named entity: dsol without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dsol"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dsol;", 
+            "description": "Named entity: dsol; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dstrok", 
+            "description": "Bad named entity: dstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dstrok;", 
+            "description": "Named entity: dstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0111"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dtdot", 
+            "description": "Bad named entity: dtdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dtdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dtdot;", 
+            "description": "Named entity: dtdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dtri", 
+            "description": "Bad named entity: dtri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dtri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dtri;", 
+            "description": "Named entity: dtri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dtrif", 
+            "description": "Bad named entity: dtrif without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dtrif"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dtrif;", 
+            "description": "Named entity: dtrif; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&duarr", 
+            "description": "Bad named entity: duarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&duarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&duarr;", 
+            "description": "Named entity: duarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&duhar", 
+            "description": "Bad named entity: duhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&duhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&duhar;", 
+            "description": "Named entity: duhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dwangle", 
+            "description": "Bad named entity: dwangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dwangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dwangle;", 
+            "description": "Named entity: dwangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29a6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dzcy", 
+            "description": "Bad named entity: dzcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dzcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dzcy;", 
+            "description": "Named entity: dzcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u045f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dzigrarr", 
+            "description": "Bad named entity: dzigrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&dzigrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&dzigrarr;", 
+            "description": "Named entity: dzigrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27ff"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eDDot", 
+            "description": "Bad named entity: eDDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eDDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eDDot;", 
+            "description": "Named entity: eDDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a77"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eDot", 
+            "description": "Bad named entity: eDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eDot;", 
+            "description": "Named entity: eDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2251"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eacute", 
+            "description": "Named entity: eacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eacute;", 
+            "description": "Named entity: eacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&easter", 
+            "description": "Bad named entity: easter without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&easter"
+                ]
+            ]
+        }, 
+        {
+            "input": "&easter;", 
+            "description": "Named entity: easter; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a6e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecaron", 
+            "description": "Bad named entity: ecaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ecaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecaron;", 
+            "description": "Named entity: ecaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u011b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecir", 
+            "description": "Bad named entity: ecir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ecir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecir;", 
+            "description": "Named entity: ecir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2256"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecirc", 
+            "description": "Named entity: ecirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ea"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecirc;", 
+            "description": "Named entity: ecirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ea"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecolon", 
+            "description": "Bad named entity: ecolon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ecolon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecolon;", 
+            "description": "Named entity: ecolon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2255"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecy", 
+            "description": "Bad named entity: ecy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ecy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ecy;", 
+            "description": "Named entity: ecy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u044d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&edot", 
+            "description": "Bad named entity: edot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&edot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&edot;", 
+            "description": "Named entity: edot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0117"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ee", 
+            "description": "Bad named entity: ee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ee;", 
+            "description": "Named entity: ee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2147"
+                ]
+            ]
+        }, 
+        {
+            "input": "&efDot", 
+            "description": "Bad named entity: efDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&efDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&efDot;", 
+            "description": "Named entity: efDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2252"
+                ]
+            ]
+        }, 
+        {
+            "input": "&efr", 
+            "description": "Bad named entity: efr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&efr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&efr;", 
+            "description": "Named entity: efr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd22"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eg", 
+            "description": "Bad named entity: eg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eg;", 
+            "description": "Named entity: eg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a9a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&egrave", 
+            "description": "Named entity: egrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00e8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&egrave;", 
+            "description": "Named entity: egrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00e8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&egs", 
+            "description": "Bad named entity: egs without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&egs"
+                ]
+            ]
+        }, 
+        {
+            "input": "&egs;", 
+            "description": "Named entity: egs; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a96"
+                ]
+            ]
+        }, 
+        {
+            "input": "&egsdot", 
+            "description": "Bad named entity: egsdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&egsdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&egsdot;", 
+            "description": "Named entity: egsdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a98"
+                ]
+            ]
+        }, 
+        {
+            "input": "&el", 
+            "description": "Bad named entity: el without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&el"
+                ]
+            ]
+        }, 
+        {
+            "input": "&el;", 
+            "description": "Named entity: el; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a99"
+                ]
+            ]
+        }, 
+        {
+            "input": "&elinters", 
+            "description": "Bad named entity: elinters without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&elinters"
+                ]
+            ]
+        }, 
+        {
+            "input": "&elinters;", 
+            "description": "Named entity: elinters; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23e7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ell", 
+            "description": "Bad named entity: ell without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ell"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ell;", 
+            "description": "Named entity: ell; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2113"
+                ]
+            ]
+        }, 
+        {
+            "input": "&els", 
+            "description": "Bad named entity: els without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&els"
+                ]
+            ]
+        }, 
+        {
+            "input": "&els;", 
+            "description": "Named entity: els; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a95"
+                ]
+            ]
+        }, 
+        {
+            "input": "&elsdot", 
+            "description": "Bad named entity: elsdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&elsdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&elsdot;", 
+            "description": "Named entity: elsdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a97"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emacr", 
+            "description": "Bad named entity: emacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&emacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emacr;", 
+            "description": "Named entity: emacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0113"
+                ]
+            ]
+        }, 
+        {
+            "input": "&empty", 
+            "description": "Bad named entity: empty without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&empty"
+                ]
+            ]
+        }, 
+        {
+            "input": "&empty;", 
+            "description": "Named entity: empty; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2205"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emptyset", 
+            "description": "Bad named entity: emptyset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&emptyset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emptyset;", 
+            "description": "Named entity: emptyset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2205"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emptyv", 
+            "description": "Bad named entity: emptyv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&emptyv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emptyv;", 
+            "description": "Named entity: emptyv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2205"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emsp", 
+            "description": "Bad named entity: emsp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&emsp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emsp13", 
+            "description": "Bad named entity: emsp13 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&emsp13"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emsp13;", 
+            "description": "Named entity: emsp13; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2004"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emsp14", 
+            "description": "Bad named entity: emsp14 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&emsp14"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emsp14;", 
+            "description": "Named entity: emsp14; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2005"
+                ]
+            ]
+        }, 
+        {
+            "input": "&emsp;", 
+            "description": "Named entity: emsp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2003"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eng", 
+            "description": "Bad named entity: eng without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eng"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eng;", 
+            "description": "Named entity: eng; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u014b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ensp", 
+            "description": "Bad named entity: ensp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ensp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ensp;", 
+            "description": "Named entity: ensp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2002"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eogon", 
+            "description": "Bad named entity: eogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eogon;", 
+            "description": "Named entity: eogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0119"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eopf", 
+            "description": "Bad named entity: eopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eopf;", 
+            "description": "Named entity: eopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd56"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epar", 
+            "description": "Bad named entity: epar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&epar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epar;", 
+            "description": "Named entity: epar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eparsl", 
+            "description": "Bad named entity: eparsl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eparsl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eparsl;", 
+            "description": "Named entity: eparsl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29e3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eplus", 
+            "description": "Bad named entity: eplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eplus;", 
+            "description": "Named entity: eplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a71"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epsi", 
+            "description": "Bad named entity: epsi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&epsi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epsi;", 
+            "description": "Named entity: epsi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epsilon", 
+            "description": "Bad named entity: epsilon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&epsilon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epsilon;", 
+            "description": "Named entity: epsilon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epsiv", 
+            "description": "Bad named entity: epsiv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&epsiv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&epsiv;", 
+            "description": "Named entity: epsiv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqcirc", 
+            "description": "Bad named entity: eqcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eqcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqcirc;", 
+            "description": "Named entity: eqcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2256"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqcolon", 
+            "description": "Bad named entity: eqcolon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eqcolon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqcolon;", 
+            "description": "Named entity: eqcolon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2255"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqsim", 
+            "description": "Bad named entity: eqsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eqsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqsim;", 
+            "description": "Named entity: eqsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2242"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqslantgtr", 
+            "description": "Bad named entity: eqslantgtr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eqslantgtr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqslantgtr;", 
+            "description": "Named entity: eqslantgtr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a96"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqslantless", 
+            "description": "Bad named entity: eqslantless without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eqslantless"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqslantless;", 
+            "description": "Named entity: eqslantless; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a95"
+                ]
+            ]
+        }, 
+        {
+            "input": "&equals", 
+            "description": "Bad named entity: equals without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&equals"
+                ]
+            ]
+        }, 
+        {
+            "input": "&equals;", 
+            "description": "Named entity: equals; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "="
+                ]
+            ]
+        }, 
+        {
+            "input": "&equest", 
+            "description": "Bad named entity: equest without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&equest"
+                ]
+            ]
+        }, 
+        {
+            "input": "&equest;", 
+            "description": "Named entity: equest; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u225f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&equiv", 
+            "description": "Bad named entity: equiv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&equiv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&equiv;", 
+            "description": "Named entity: equiv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2261"
+                ]
+            ]
+        }, 
+        {
+            "input": "&equivDD", 
+            "description": "Bad named entity: equivDD without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&equivDD"
+                ]
+            ]
+        }, 
+        {
+            "input": "&equivDD;", 
+            "description": "Named entity: equivDD; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a78"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqvparsl", 
+            "description": "Bad named entity: eqvparsl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eqvparsl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eqvparsl;", 
+            "description": "Named entity: eqvparsl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&erDot", 
+            "description": "Bad named entity: erDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&erDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&erDot;", 
+            "description": "Named entity: erDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2253"
+                ]
+            ]
+        }, 
+        {
+            "input": "&erarr", 
+            "description": "Bad named entity: erarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&erarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&erarr;", 
+            "description": "Named entity: erarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2971"
+                ]
+            ]
+        }, 
+        {
+            "input": "&escr", 
+            "description": "Bad named entity: escr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&escr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&escr;", 
+            "description": "Named entity: escr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u212f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&esdot", 
+            "description": "Bad named entity: esdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&esdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&esdot;", 
+            "description": "Named entity: esdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2250"
+                ]
+            ]
+        }, 
+        {
+            "input": "&esim", 
+            "description": "Bad named entity: esim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&esim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&esim;", 
+            "description": "Named entity: esim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2242"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eta", 
+            "description": "Bad named entity: eta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&eta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eta;", 
+            "description": "Named entity: eta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eth", 
+            "description": "Named entity: eth without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&eth;", 
+            "description": "Named entity: eth; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&euml", 
+            "description": "Named entity: euml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&euml;", 
+            "description": "Named entity: euml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&euro", 
+            "description": "Bad named entity: euro without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&euro"
+                ]
+            ]
+        }, 
+        {
+            "input": "&euro;", 
+            "description": "Named entity: euro; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u20ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&excl", 
+            "description": "Bad named entity: excl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&excl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&excl;", 
+            "description": "Named entity: excl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "!"
+                ]
+            ]
+        }, 
+        {
+            "input": "&exist", 
+            "description": "Bad named entity: exist without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&exist"
+                ]
+            ]
+        }, 
+        {
+            "input": "&exist;", 
+            "description": "Named entity: exist; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2203"
+                ]
+            ]
+        }, 
+        {
+            "input": "&expectation", 
+            "description": "Bad named entity: expectation without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&expectation"
+                ]
+            ]
+        }, 
+        {
+            "input": "&expectation;", 
+            "description": "Named entity: expectation; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2130"
+                ]
+            ]
+        }, 
+        {
+            "input": "&exponentiale", 
+            "description": "Bad named entity: exponentiale without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&exponentiale"
+                ]
+            ]
+        }, 
+        {
+            "input": "&exponentiale;", 
+            "description": "Named entity: exponentiale; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2147"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fallingdotseq", 
+            "description": "Bad named entity: fallingdotseq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fallingdotseq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fallingdotseq;", 
+            "description": "Named entity: fallingdotseq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2252"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fcy", 
+            "description": "Bad named entity: fcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fcy;", 
+            "description": "Named entity: fcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0444"
+                ]
+            ]
+        }, 
+        {
+            "input": "&female", 
+            "description": "Bad named entity: female without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&female"
+                ]
+            ]
+        }, 
+        {
+            "input": "&female;", 
+            "description": "Named entity: female; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2640"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ffilig", 
+            "description": "Bad named entity: ffilig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ffilig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ffilig;", 
+            "description": "Named entity: ffilig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ufb03"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fflig", 
+            "description": "Bad named entity: fflig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fflig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fflig;", 
+            "description": "Named entity: fflig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ufb00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ffllig", 
+            "description": "Bad named entity: ffllig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ffllig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ffllig;", 
+            "description": "Named entity: ffllig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ufb04"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ffr", 
+            "description": "Bad named entity: ffr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ffr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ffr;", 
+            "description": "Named entity: ffr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd23"
+                ]
+            ]
+        }, 
+        {
+            "input": "&filig", 
+            "description": "Bad named entity: filig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&filig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&filig;", 
+            "description": "Named entity: filig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ufb01"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fjlig", 
+            "description": "Bad named entity: fjlig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fjlig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fjlig;", 
+            "description": "Named entity: fjlig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "fj"
+                ]
+            ]
+        }, 
+        {
+            "input": "&flat", 
+            "description": "Bad named entity: flat without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&flat"
+                ]
+            ]
+        }, 
+        {
+            "input": "&flat;", 
+            "description": "Named entity: flat; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u266d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fllig", 
+            "description": "Bad named entity: fllig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fllig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fllig;", 
+            "description": "Named entity: fllig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ufb02"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fltns", 
+            "description": "Bad named entity: fltns without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fltns"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fltns;", 
+            "description": "Named entity: fltns; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fnof", 
+            "description": "Bad named entity: fnof without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fnof"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fnof;", 
+            "description": "Named entity: fnof; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0192"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fopf", 
+            "description": "Bad named entity: fopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fopf;", 
+            "description": "Named entity: fopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd57"
+                ]
+            ]
+        }, 
+        {
+            "input": "&forall", 
+            "description": "Bad named entity: forall without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&forall"
+                ]
+            ]
+        }, 
+        {
+            "input": "&forall;", 
+            "description": "Named entity: forall; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2200"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fork", 
+            "description": "Bad named entity: fork without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fork"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fork;", 
+            "description": "Named entity: fork; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&forkv", 
+            "description": "Bad named entity: forkv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&forkv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&forkv;", 
+            "description": "Named entity: forkv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fpartint", 
+            "description": "Bad named entity: fpartint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fpartint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fpartint;", 
+            "description": "Named entity: fpartint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a0d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac12", 
+            "description": "Named entity: frac12 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac12;", 
+            "description": "Named entity: frac12; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac13", 
+            "description": "Bad named entity: frac13 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac13"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac13;", 
+            "description": "Named entity: frac13; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2153"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac14", 
+            "description": "Named entity: frac14 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00bc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac14;", 
+            "description": "Named entity: frac14; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00bc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac15", 
+            "description": "Bad named entity: frac15 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac15"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac15;", 
+            "description": "Named entity: frac15; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2155"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac16", 
+            "description": "Bad named entity: frac16 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac16"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac16;", 
+            "description": "Named entity: frac16; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2159"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac18", 
+            "description": "Bad named entity: frac18 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac18"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac18;", 
+            "description": "Named entity: frac18; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u215b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac23", 
+            "description": "Bad named entity: frac23 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac23"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac23;", 
+            "description": "Named entity: frac23; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2154"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac25", 
+            "description": "Bad named entity: frac25 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac25"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac25;", 
+            "description": "Named entity: frac25; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2156"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac34", 
+            "description": "Named entity: frac34 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac34;", 
+            "description": "Named entity: frac34; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac35", 
+            "description": "Bad named entity: frac35 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac35"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac35;", 
+            "description": "Named entity: frac35; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2157"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac38", 
+            "description": "Bad named entity: frac38 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac38"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac38;", 
+            "description": "Named entity: frac38; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u215c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac45", 
+            "description": "Bad named entity: frac45 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac45"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac45;", 
+            "description": "Named entity: frac45; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2158"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac56", 
+            "description": "Bad named entity: frac56 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac56"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac56;", 
+            "description": "Named entity: frac56; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u215a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac58", 
+            "description": "Bad named entity: frac58 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac58"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac58;", 
+            "description": "Named entity: frac58; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u215d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac78", 
+            "description": "Bad named entity: frac78 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frac78"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frac78;", 
+            "description": "Named entity: frac78; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u215e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frasl", 
+            "description": "Bad named entity: frasl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frasl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frasl;", 
+            "description": "Named entity: frasl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2044"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frown", 
+            "description": "Bad named entity: frown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&frown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&frown;", 
+            "description": "Named entity: frown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2322"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fscr", 
+            "description": "Bad named entity: fscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&fscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&fscr;", 
+            "description": "Named entity: fscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcbb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gE", 
+            "description": "Bad named entity: gE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gE;", 
+            "description": "Named entity: gE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2267"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gEl", 
+            "description": "Bad named entity: gEl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gEl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gEl;", 
+            "description": "Named entity: gEl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gacute", 
+            "description": "Bad named entity: gacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gacute;", 
+            "description": "Named entity: gacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u01f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gamma", 
+            "description": "Bad named entity: gamma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gamma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gamma;", 
+            "description": "Named entity: gamma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gammad", 
+            "description": "Bad named entity: gammad without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gammad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gammad;", 
+            "description": "Named entity: gammad; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gap", 
+            "description": "Bad named entity: gap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gap;", 
+            "description": "Named entity: gap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a86"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gbreve", 
+            "description": "Bad named entity: gbreve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gbreve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gbreve;", 
+            "description": "Named entity: gbreve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u011f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gcirc", 
+            "description": "Bad named entity: gcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gcirc;", 
+            "description": "Named entity: gcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u011d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gcy", 
+            "description": "Bad named entity: gcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gcy;", 
+            "description": "Named entity: gcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0433"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gdot", 
+            "description": "Bad named entity: gdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gdot;", 
+            "description": "Named entity: gdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0121"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ge", 
+            "description": "Bad named entity: ge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ge;", 
+            "description": "Named entity: ge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2265"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gel", 
+            "description": "Bad named entity: gel without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gel"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gel;", 
+            "description": "Named entity: gel; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&geq", 
+            "description": "Bad named entity: geq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&geq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&geq;", 
+            "description": "Named entity: geq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2265"
+                ]
+            ]
+        }, 
+        {
+            "input": "&geqq", 
+            "description": "Bad named entity: geqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&geqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&geqq;", 
+            "description": "Named entity: geqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2267"
+                ]
+            ]
+        }, 
+        {
+            "input": "&geqslant", 
+            "description": "Bad named entity: geqslant without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&geqslant"
+                ]
+            ]
+        }, 
+        {
+            "input": "&geqslant;", 
+            "description": "Named entity: geqslant; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ges", 
+            "description": "Bad named entity: ges without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ges"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ges;", 
+            "description": "Named entity: ges; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gescc", 
+            "description": "Bad named entity: gescc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gescc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gescc;", 
+            "description": "Named entity: gescc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesdot", 
+            "description": "Bad named entity: gesdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gesdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesdot;", 
+            "description": "Named entity: gesdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a80"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesdoto", 
+            "description": "Bad named entity: gesdoto without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gesdoto"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesdoto;", 
+            "description": "Named entity: gesdoto; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a82"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesdotol", 
+            "description": "Bad named entity: gesdotol without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gesdotol"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesdotol;", 
+            "description": "Named entity: gesdotol; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a84"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesl", 
+            "description": "Bad named entity: gesl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gesl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesl;", 
+            "description": "Named entity: gesl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22db\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesles", 
+            "description": "Bad named entity: gesles without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gesles"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gesles;", 
+            "description": "Named entity: gesles; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a94"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gfr", 
+            "description": "Bad named entity: gfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gfr;", 
+            "description": "Named entity: gfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd24"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gg", 
+            "description": "Bad named entity: gg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gg;", 
+            "description": "Named entity: gg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ggg", 
+            "description": "Bad named entity: ggg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ggg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ggg;", 
+            "description": "Named entity: ggg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gimel", 
+            "description": "Bad named entity: gimel without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gimel"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gimel;", 
+            "description": "Named entity: gimel; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2137"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gjcy", 
+            "description": "Bad named entity: gjcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gjcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gjcy;", 
+            "description": "Named entity: gjcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0453"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gl", 
+            "description": "Bad named entity: gl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gl;", 
+            "description": "Named entity: gl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2277"
+                ]
+            ]
+        }, 
+        {
+            "input": "&glE", 
+            "description": "Bad named entity: glE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&glE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&glE;", 
+            "description": "Named entity: glE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a92"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gla", 
+            "description": "Bad named entity: gla without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gla"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gla;", 
+            "description": "Named entity: gla; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&glj", 
+            "description": "Bad named entity: glj without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&glj"
+                ]
+            ]
+        }, 
+        {
+            "input": "&glj;", 
+            "description": "Named entity: glj; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnE", 
+            "description": "Bad named entity: gnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnE;", 
+            "description": "Named entity: gnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2269"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnap", 
+            "description": "Bad named entity: gnap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gnap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnap;", 
+            "description": "Named entity: gnap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnapprox", 
+            "description": "Bad named entity: gnapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gnapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnapprox;", 
+            "description": "Named entity: gnapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gne", 
+            "description": "Bad named entity: gne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gne;", 
+            "description": "Named entity: gne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a88"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gneq", 
+            "description": "Bad named entity: gneq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gneq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gneq;", 
+            "description": "Named entity: gneq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a88"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gneqq", 
+            "description": "Bad named entity: gneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gneqq;", 
+            "description": "Named entity: gneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2269"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnsim", 
+            "description": "Bad named entity: gnsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gnsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gnsim;", 
+            "description": "Named entity: gnsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gopf", 
+            "description": "Bad named entity: gopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gopf;", 
+            "description": "Named entity: gopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd58"
+                ]
+            ]
+        }, 
+        {
+            "input": "&grave", 
+            "description": "Bad named entity: grave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&grave"
+                ]
+            ]
+        }, 
+        {
+            "input": "&grave;", 
+            "description": "Named entity: grave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "`"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gscr", 
+            "description": "Bad named entity: gscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gscr;", 
+            "description": "Named entity: gscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gsim", 
+            "description": "Bad named entity: gsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gsim;", 
+            "description": "Named entity: gsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2273"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gsime", 
+            "description": "Bad named entity: gsime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gsime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gsime;", 
+            "description": "Named entity: gsime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gsiml", 
+            "description": "Bad named entity: gsiml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gsiml"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gsiml;", 
+            "description": "Named entity: gsiml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a90"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gt", 
+            "description": "Named entity: gt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    ">"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gt;", 
+            "description": "Named entity: gt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    ">"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtcc;", 
+            "description": "Named entity: gtcc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtcir;", 
+            "description": "Named entity: gtcir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtdot;", 
+            "description": "Named entity: gtdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtlPar;", 
+            "description": "Named entity: gtlPar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2995"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtquest;", 
+            "description": "Named entity: gtquest; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtrapprox;", 
+            "description": "Named entity: gtrapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a86"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtrarr;", 
+            "description": "Named entity: gtrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2978"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtrdot;", 
+            "description": "Named entity: gtrdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtreqless;", 
+            "description": "Named entity: gtreqless; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtreqqless;", 
+            "description": "Named entity: gtreqqless; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtrless;", 
+            "description": "Named entity: gtrless; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2277"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gtrsim;", 
+            "description": "Named entity: gtrsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2273"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gvertneqq", 
+            "description": "Bad named entity: gvertneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gvertneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gvertneqq;", 
+            "description": "Named entity: gvertneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2269\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gvnE", 
+            "description": "Bad named entity: gvnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&gvnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&gvnE;", 
+            "description": "Named entity: gvnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2269\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hArr", 
+            "description": "Bad named entity: hArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hArr;", 
+            "description": "Named entity: hArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hairsp", 
+            "description": "Bad named entity: hairsp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hairsp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hairsp;", 
+            "description": "Named entity: hairsp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&half", 
+            "description": "Bad named entity: half without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&half"
+                ]
+            ]
+        }, 
+        {
+            "input": "&half;", 
+            "description": "Named entity: half; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hamilt", 
+            "description": "Bad named entity: hamilt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hamilt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hamilt;", 
+            "description": "Named entity: hamilt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hardcy", 
+            "description": "Bad named entity: hardcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hardcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hardcy;", 
+            "description": "Named entity: hardcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u044a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&harr", 
+            "description": "Bad named entity: harr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&harr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&harr;", 
+            "description": "Named entity: harr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2194"
+                ]
+            ]
+        }, 
+        {
+            "input": "&harrcir", 
+            "description": "Bad named entity: harrcir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&harrcir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&harrcir;", 
+            "description": "Named entity: harrcir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2948"
+                ]
+            ]
+        }, 
+        {
+            "input": "&harrw", 
+            "description": "Bad named entity: harrw without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&harrw"
+                ]
+            ]
+        }, 
+        {
+            "input": "&harrw;", 
+            "description": "Named entity: harrw; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hbar", 
+            "description": "Bad named entity: hbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hbar;", 
+            "description": "Named entity: hbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hcirc", 
+            "description": "Bad named entity: hcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hcirc;", 
+            "description": "Named entity: hcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0125"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hearts", 
+            "description": "Bad named entity: hearts without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hearts"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hearts;", 
+            "description": "Named entity: hearts; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2665"
+                ]
+            ]
+        }, 
+        {
+            "input": "&heartsuit", 
+            "description": "Bad named entity: heartsuit without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&heartsuit"
+                ]
+            ]
+        }, 
+        {
+            "input": "&heartsuit;", 
+            "description": "Named entity: heartsuit; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2665"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hellip", 
+            "description": "Bad named entity: hellip without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hellip"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hellip;", 
+            "description": "Named entity: hellip; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2026"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hercon", 
+            "description": "Bad named entity: hercon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hercon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hercon;", 
+            "description": "Named entity: hercon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hfr", 
+            "description": "Bad named entity: hfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hfr;", 
+            "description": "Named entity: hfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd25"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hksearow", 
+            "description": "Bad named entity: hksearow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hksearow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hksearow;", 
+            "description": "Named entity: hksearow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2925"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hkswarow", 
+            "description": "Bad named entity: hkswarow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hkswarow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hkswarow;", 
+            "description": "Named entity: hkswarow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2926"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hoarr", 
+            "description": "Bad named entity: hoarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hoarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hoarr;", 
+            "description": "Named entity: hoarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ff"
+                ]
+            ]
+        }, 
+        {
+            "input": "&homtht", 
+            "description": "Bad named entity: homtht without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&homtht"
+                ]
+            ]
+        }, 
+        {
+            "input": "&homtht;", 
+            "description": "Named entity: homtht; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hookleftarrow", 
+            "description": "Bad named entity: hookleftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hookleftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hookleftarrow;", 
+            "description": "Named entity: hookleftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hookrightarrow", 
+            "description": "Bad named entity: hookrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hookrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hookrightarrow;", 
+            "description": "Named entity: hookrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hopf", 
+            "description": "Bad named entity: hopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hopf;", 
+            "description": "Named entity: hopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd59"
+                ]
+            ]
+        }, 
+        {
+            "input": "&horbar", 
+            "description": "Bad named entity: horbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&horbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&horbar;", 
+            "description": "Named entity: horbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2015"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hscr", 
+            "description": "Bad named entity: hscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hscr;", 
+            "description": "Named entity: hscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcbd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hslash", 
+            "description": "Bad named entity: hslash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hslash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hslash;", 
+            "description": "Named entity: hslash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hstrok", 
+            "description": "Bad named entity: hstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hstrok;", 
+            "description": "Named entity: hstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0127"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hybull", 
+            "description": "Bad named entity: hybull without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hybull"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hybull;", 
+            "description": "Named entity: hybull; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2043"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hyphen", 
+            "description": "Bad named entity: hyphen without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&hyphen"
+                ]
+            ]
+        }, 
+        {
+            "input": "&hyphen;", 
+            "description": "Named entity: hyphen; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2010"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iacute", 
+            "description": "Named entity: iacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iacute;", 
+            "description": "Named entity: iacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ic", 
+            "description": "Bad named entity: ic without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ic"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ic;", 
+            "description": "Named entity: ic; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2063"
+                ]
+            ]
+        }, 
+        {
+            "input": "&icirc", 
+            "description": "Named entity: icirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&icirc;", 
+            "description": "Named entity: icirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&icy", 
+            "description": "Bad named entity: icy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&icy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&icy;", 
+            "description": "Named entity: icy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0438"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iecy", 
+            "description": "Bad named entity: iecy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iecy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iecy;", 
+            "description": "Named entity: iecy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0435"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iexcl", 
+            "description": "Named entity: iexcl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iexcl;", 
+            "description": "Named entity: iexcl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iff", 
+            "description": "Bad named entity: iff without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iff"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iff;", 
+            "description": "Named entity: iff; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ifr", 
+            "description": "Bad named entity: ifr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ifr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ifr;", 
+            "description": "Named entity: ifr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd26"
+                ]
+            ]
+        }, 
+        {
+            "input": "&igrave", 
+            "description": "Named entity: igrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&igrave;", 
+            "description": "Named entity: igrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ii", 
+            "description": "Bad named entity: ii without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ii"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ii;", 
+            "description": "Named entity: ii; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2148"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iiiint", 
+            "description": "Bad named entity: iiiint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iiiint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iiiint;", 
+            "description": "Named entity: iiiint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a0c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iiint", 
+            "description": "Bad named entity: iiint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iiint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iiint;", 
+            "description": "Named entity: iiint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iinfin", 
+            "description": "Bad named entity: iinfin without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iinfin"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iinfin;", 
+            "description": "Named entity: iinfin; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iiota", 
+            "description": "Bad named entity: iiota without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iiota"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iiota;", 
+            "description": "Named entity: iiota; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2129"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ijlig", 
+            "description": "Bad named entity: ijlig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ijlig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ijlig;", 
+            "description": "Named entity: ijlig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0133"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imacr", 
+            "description": "Bad named entity: imacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&imacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imacr;", 
+            "description": "Named entity: imacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u012b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&image", 
+            "description": "Bad named entity: image without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&image"
+                ]
+            ]
+        }, 
+        {
+            "input": "&image;", 
+            "description": "Named entity: image; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2111"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imagline", 
+            "description": "Bad named entity: imagline without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&imagline"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imagline;", 
+            "description": "Named entity: imagline; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2110"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imagpart", 
+            "description": "Bad named entity: imagpart without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&imagpart"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imagpart;", 
+            "description": "Named entity: imagpart; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2111"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imath", 
+            "description": "Bad named entity: imath without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&imath"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imath;", 
+            "description": "Named entity: imath; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0131"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imof", 
+            "description": "Bad named entity: imof without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&imof"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imof;", 
+            "description": "Named entity: imof; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imped", 
+            "description": "Bad named entity: imped without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&imped"
+                ]
+            ]
+        }, 
+        {
+            "input": "&imped;", 
+            "description": "Named entity: imped; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u01b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&in", 
+            "description": "Bad named entity: in without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&in"
+                ]
+            ]
+        }, 
+        {
+            "input": "&in;", 
+            "description": "Named entity: in; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2208"
+                ]
+            ]
+        }, 
+        {
+            "input": "&incare", 
+            "description": "Bad named entity: incare without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&incare"
+                ]
+            ]
+        }, 
+        {
+            "input": "&incare;", 
+            "description": "Named entity: incare; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2105"
+                ]
+            ]
+        }, 
+        {
+            "input": "&infin", 
+            "description": "Bad named entity: infin without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&infin"
+                ]
+            ]
+        }, 
+        {
+            "input": "&infin;", 
+            "description": "Named entity: infin; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&infintie", 
+            "description": "Bad named entity: infintie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&infintie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&infintie;", 
+            "description": "Named entity: infintie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&inodot", 
+            "description": "Bad named entity: inodot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&inodot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&inodot;", 
+            "description": "Named entity: inodot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0131"
+                ]
+            ]
+        }, 
+        {
+            "input": "&int", 
+            "description": "Bad named entity: int without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&int"
+                ]
+            ]
+        }, 
+        {
+            "input": "&int;", 
+            "description": "Named entity: int; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intcal", 
+            "description": "Bad named entity: intcal without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&intcal"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intcal;", 
+            "description": "Named entity: intcal; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&integers", 
+            "description": "Bad named entity: integers without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&integers"
+                ]
+            ]
+        }, 
+        {
+            "input": "&integers;", 
+            "description": "Named entity: integers; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2124"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intercal", 
+            "description": "Bad named entity: intercal without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&intercal"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intercal;", 
+            "description": "Named entity: intercal; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intlarhk", 
+            "description": "Bad named entity: intlarhk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&intlarhk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intlarhk;", 
+            "description": "Named entity: intlarhk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a17"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intprod", 
+            "description": "Bad named entity: intprod without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&intprod"
+                ]
+            ]
+        }, 
+        {
+            "input": "&intprod;", 
+            "description": "Named entity: intprod; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a3c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iocy", 
+            "description": "Bad named entity: iocy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iocy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iocy;", 
+            "description": "Named entity: iocy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0451"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iogon", 
+            "description": "Bad named entity: iogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iogon;", 
+            "description": "Named entity: iogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u012f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iopf", 
+            "description": "Bad named entity: iopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iopf;", 
+            "description": "Named entity: iopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd5a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iota", 
+            "description": "Bad named entity: iota without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iota"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iota;", 
+            "description": "Named entity: iota; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iprod", 
+            "description": "Bad named entity: iprod without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iprod"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iprod;", 
+            "description": "Named entity: iprod; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a3c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iquest", 
+            "description": "Named entity: iquest without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iquest;", 
+            "description": "Named entity: iquest; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iscr", 
+            "description": "Bad named entity: iscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iscr;", 
+            "description": "Named entity: iscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcbe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isin", 
+            "description": "Bad named entity: isin without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&isin"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isin;", 
+            "description": "Named entity: isin; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2208"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isinE", 
+            "description": "Bad named entity: isinE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&isinE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isinE;", 
+            "description": "Named entity: isinE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isindot", 
+            "description": "Bad named entity: isindot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&isindot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isindot;", 
+            "description": "Named entity: isindot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isins", 
+            "description": "Bad named entity: isins without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&isins"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isins;", 
+            "description": "Named entity: isins; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isinsv", 
+            "description": "Bad named entity: isinsv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&isinsv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isinsv;", 
+            "description": "Named entity: isinsv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isinv", 
+            "description": "Bad named entity: isinv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&isinv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&isinv;", 
+            "description": "Named entity: isinv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2208"
+                ]
+            ]
+        }, 
+        {
+            "input": "&it", 
+            "description": "Bad named entity: it without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&it"
+                ]
+            ]
+        }, 
+        {
+            "input": "&it;", 
+            "description": "Named entity: it; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2062"
+                ]
+            ]
+        }, 
+        {
+            "input": "&itilde", 
+            "description": "Bad named entity: itilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&itilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&itilde;", 
+            "description": "Named entity: itilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0129"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iukcy", 
+            "description": "Bad named entity: iukcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&iukcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iukcy;", 
+            "description": "Named entity: iukcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0456"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iuml", 
+            "description": "Named entity: iuml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ef"
+                ]
+            ]
+        }, 
+        {
+            "input": "&iuml;", 
+            "description": "Named entity: iuml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ef"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jcirc", 
+            "description": "Bad named entity: jcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jcirc;", 
+            "description": "Named entity: jcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0135"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jcy", 
+            "description": "Bad named entity: jcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jcy;", 
+            "description": "Named entity: jcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0439"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jfr", 
+            "description": "Bad named entity: jfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jfr;", 
+            "description": "Named entity: jfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd27"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jmath", 
+            "description": "Bad named entity: jmath without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jmath"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jmath;", 
+            "description": "Named entity: jmath; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0237"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jopf", 
+            "description": "Bad named entity: jopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jopf;", 
+            "description": "Named entity: jopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd5b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jscr", 
+            "description": "Bad named entity: jscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jscr;", 
+            "description": "Named entity: jscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcbf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jsercy", 
+            "description": "Bad named entity: jsercy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jsercy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jsercy;", 
+            "description": "Named entity: jsercy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0458"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jukcy", 
+            "description": "Bad named entity: jukcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&jukcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&jukcy;", 
+            "description": "Named entity: jukcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0454"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kappa", 
+            "description": "Bad named entity: kappa without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kappa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kappa;", 
+            "description": "Named entity: kappa; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03ba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kappav", 
+            "description": "Bad named entity: kappav without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kappav"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kappav;", 
+            "description": "Named entity: kappav; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kcedil", 
+            "description": "Bad named entity: kcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kcedil;", 
+            "description": "Named entity: kcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0137"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kcy", 
+            "description": "Bad named entity: kcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kcy;", 
+            "description": "Named entity: kcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u043a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kfr", 
+            "description": "Bad named entity: kfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kfr;", 
+            "description": "Named entity: kfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd28"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kgreen", 
+            "description": "Bad named entity: kgreen without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kgreen"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kgreen;", 
+            "description": "Named entity: kgreen; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0138"
+                ]
+            ]
+        }, 
+        {
+            "input": "&khcy", 
+            "description": "Bad named entity: khcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&khcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&khcy;", 
+            "description": "Named entity: khcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0445"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kjcy", 
+            "description": "Bad named entity: kjcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kjcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kjcy;", 
+            "description": "Named entity: kjcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u045c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kopf", 
+            "description": "Bad named entity: kopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kopf;", 
+            "description": "Named entity: kopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd5c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kscr", 
+            "description": "Bad named entity: kscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&kscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&kscr;", 
+            "description": "Named entity: kscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lAarr", 
+            "description": "Bad named entity: lAarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lAarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lAarr;", 
+            "description": "Named entity: lAarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lArr", 
+            "description": "Bad named entity: lArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lArr;", 
+            "description": "Named entity: lArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lAtail", 
+            "description": "Bad named entity: lAtail without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lAtail"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lAtail;", 
+            "description": "Named entity: lAtail; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u291b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lBarr", 
+            "description": "Bad named entity: lBarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lBarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lBarr;", 
+            "description": "Named entity: lBarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u290e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lE", 
+            "description": "Bad named entity: lE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lE;", 
+            "description": "Named entity: lE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2266"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lEg", 
+            "description": "Bad named entity: lEg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lEg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lEg;", 
+            "description": "Named entity: lEg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lHar", 
+            "description": "Bad named entity: lHar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lHar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lHar;", 
+            "description": "Named entity: lHar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2962"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lacute", 
+            "description": "Bad named entity: lacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lacute;", 
+            "description": "Named entity: lacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u013a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&laemptyv", 
+            "description": "Bad named entity: laemptyv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&laemptyv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&laemptyv;", 
+            "description": "Named entity: laemptyv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lagran", 
+            "description": "Bad named entity: lagran without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lagran"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lagran;", 
+            "description": "Named entity: lagran; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2112"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lambda", 
+            "description": "Bad named entity: lambda without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lambda"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lambda;", 
+            "description": "Named entity: lambda; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03bb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lang", 
+            "description": "Bad named entity: lang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lang;", 
+            "description": "Named entity: lang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&langd", 
+            "description": "Bad named entity: langd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&langd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&langd;", 
+            "description": "Named entity: langd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2991"
+                ]
+            ]
+        }, 
+        {
+            "input": "&langle", 
+            "description": "Bad named entity: langle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&langle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&langle;", 
+            "description": "Named entity: langle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lap", 
+            "description": "Bad named entity: lap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lap;", 
+            "description": "Named entity: lap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a85"
+                ]
+            ]
+        }, 
+        {
+            "input": "&laquo", 
+            "description": "Named entity: laquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&laquo;", 
+            "description": "Named entity: laquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larr", 
+            "description": "Bad named entity: larr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larr;", 
+            "description": "Named entity: larr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2190"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrb", 
+            "description": "Bad named entity: larrb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrb;", 
+            "description": "Named entity: larrb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21e4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrbfs", 
+            "description": "Bad named entity: larrbfs without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrbfs"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrbfs;", 
+            "description": "Named entity: larrbfs; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u291f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrfs", 
+            "description": "Bad named entity: larrfs without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrfs"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrfs;", 
+            "description": "Named entity: larrfs; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u291d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrhk", 
+            "description": "Bad named entity: larrhk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrhk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrhk;", 
+            "description": "Named entity: larrhk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrlp", 
+            "description": "Bad named entity: larrlp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrlp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrlp;", 
+            "description": "Named entity: larrlp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrpl", 
+            "description": "Bad named entity: larrpl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrpl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrpl;", 
+            "description": "Named entity: larrpl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2939"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrsim", 
+            "description": "Bad named entity: larrsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrsim;", 
+            "description": "Named entity: larrsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2973"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrtl", 
+            "description": "Bad named entity: larrtl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&larrtl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&larrtl;", 
+            "description": "Named entity: larrtl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lat", 
+            "description": "Bad named entity: lat without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lat"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lat;", 
+            "description": "Named entity: lat; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&latail", 
+            "description": "Bad named entity: latail without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&latail"
+                ]
+            ]
+        }, 
+        {
+            "input": "&latail;", 
+            "description": "Named entity: latail; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2919"
+                ]
+            ]
+        }, 
+        {
+            "input": "&late", 
+            "description": "Bad named entity: late without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&late"
+                ]
+            ]
+        }, 
+        {
+            "input": "&late;", 
+            "description": "Named entity: late; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lates", 
+            "description": "Bad named entity: lates without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lates"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lates;", 
+            "description": "Named entity: lates; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aad\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbarr", 
+            "description": "Bad named entity: lbarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lbarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbarr;", 
+            "description": "Named entity: lbarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u290c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbbrk", 
+            "description": "Bad named entity: lbbrk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lbbrk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbbrk;", 
+            "description": "Named entity: lbbrk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2772"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrace", 
+            "description": "Bad named entity: lbrace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lbrace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrace;", 
+            "description": "Named entity: lbrace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "{"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrack", 
+            "description": "Bad named entity: lbrack without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lbrack"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrack;", 
+            "description": "Named entity: lbrack; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "["
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrke", 
+            "description": "Bad named entity: lbrke without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lbrke"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrke;", 
+            "description": "Named entity: lbrke; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u298b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrksld", 
+            "description": "Bad named entity: lbrksld without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lbrksld"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrksld;", 
+            "description": "Named entity: lbrksld; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u298f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrkslu", 
+            "description": "Bad named entity: lbrkslu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lbrkslu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lbrkslu;", 
+            "description": "Named entity: lbrkslu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u298d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcaron", 
+            "description": "Bad named entity: lcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcaron;", 
+            "description": "Named entity: lcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u013e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcedil", 
+            "description": "Bad named entity: lcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcedil;", 
+            "description": "Named entity: lcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u013c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lceil", 
+            "description": "Bad named entity: lceil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lceil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lceil;", 
+            "description": "Named entity: lceil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2308"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcub", 
+            "description": "Bad named entity: lcub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lcub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcub;", 
+            "description": "Named entity: lcub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "{"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcy", 
+            "description": "Bad named entity: lcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lcy;", 
+            "description": "Named entity: lcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u043b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldca", 
+            "description": "Bad named entity: ldca without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ldca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldca;", 
+            "description": "Named entity: ldca; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2936"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldquo", 
+            "description": "Bad named entity: ldquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ldquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldquo;", 
+            "description": "Named entity: ldquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldquor", 
+            "description": "Bad named entity: ldquor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ldquor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldquor;", 
+            "description": "Named entity: ldquor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldrdhar", 
+            "description": "Bad named entity: ldrdhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ldrdhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldrdhar;", 
+            "description": "Named entity: ldrdhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2967"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldrushar", 
+            "description": "Bad named entity: ldrushar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ldrushar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldrushar;", 
+            "description": "Named entity: ldrushar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u294b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldsh", 
+            "description": "Bad named entity: ldsh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ldsh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ldsh;", 
+            "description": "Named entity: ldsh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&le", 
+            "description": "Bad named entity: le without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&le"
+                ]
+            ]
+        }, 
+        {
+            "input": "&le;", 
+            "description": "Named entity: le; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2264"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftarrow", 
+            "description": "Bad named entity: leftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftarrow;", 
+            "description": "Named entity: leftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2190"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftarrowtail", 
+            "description": "Bad named entity: leftarrowtail without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftarrowtail"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftarrowtail;", 
+            "description": "Named entity: leftarrowtail; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftharpoondown", 
+            "description": "Bad named entity: leftharpoondown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftharpoondown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftharpoondown;", 
+            "description": "Named entity: leftharpoondown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftharpoonup", 
+            "description": "Bad named entity: leftharpoonup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftharpoonup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftharpoonup;", 
+            "description": "Named entity: leftharpoonup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftleftarrows", 
+            "description": "Bad named entity: leftleftarrows without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftleftarrows"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftleftarrows;", 
+            "description": "Named entity: leftleftarrows; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightarrow", 
+            "description": "Bad named entity: leftrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightarrow;", 
+            "description": "Named entity: leftrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2194"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightarrows", 
+            "description": "Bad named entity: leftrightarrows without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftrightarrows"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightarrows;", 
+            "description": "Named entity: leftrightarrows; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightharpoons", 
+            "description": "Bad named entity: leftrightharpoons without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftrightharpoons"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightharpoons;", 
+            "description": "Named entity: leftrightharpoons; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightsquigarrow", 
+            "description": "Bad named entity: leftrightsquigarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftrightsquigarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftrightsquigarrow;", 
+            "description": "Named entity: leftrightsquigarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftthreetimes", 
+            "description": "Bad named entity: leftthreetimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leftthreetimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leftthreetimes;", 
+            "description": "Named entity: leftthreetimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leg", 
+            "description": "Bad named entity: leg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leg;", 
+            "description": "Named entity: leg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leq", 
+            "description": "Bad named entity: leq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leq;", 
+            "description": "Named entity: leq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2264"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leqq", 
+            "description": "Bad named entity: leqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leqq;", 
+            "description": "Named entity: leqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2266"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leqslant", 
+            "description": "Bad named entity: leqslant without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&leqslant"
+                ]
+            ]
+        }, 
+        {
+            "input": "&leqslant;", 
+            "description": "Named entity: leqslant; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&les", 
+            "description": "Bad named entity: les without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&les"
+                ]
+            ]
+        }, 
+        {
+            "input": "&les;", 
+            "description": "Named entity: les; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lescc", 
+            "description": "Bad named entity: lescc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lescc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lescc;", 
+            "description": "Named entity: lescc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesdot", 
+            "description": "Bad named entity: lesdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesdot;", 
+            "description": "Named entity: lesdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesdoto", 
+            "description": "Bad named entity: lesdoto without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesdoto"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesdoto;", 
+            "description": "Named entity: lesdoto; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a81"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesdotor", 
+            "description": "Bad named entity: lesdotor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesdotor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesdotor;", 
+            "description": "Named entity: lesdotor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a83"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesg", 
+            "description": "Bad named entity: lesg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesg;", 
+            "description": "Named entity: lesg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22da\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesges", 
+            "description": "Bad named entity: lesges without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesges"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesges;", 
+            "description": "Named entity: lesges; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a93"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lessapprox", 
+            "description": "Bad named entity: lessapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lessapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lessapprox;", 
+            "description": "Named entity: lessapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a85"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lessdot", 
+            "description": "Bad named entity: lessdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lessdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lessdot;", 
+            "description": "Named entity: lessdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesseqgtr", 
+            "description": "Bad named entity: lesseqgtr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesseqgtr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesseqgtr;", 
+            "description": "Named entity: lesseqgtr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesseqqgtr", 
+            "description": "Bad named entity: lesseqqgtr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesseqqgtr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesseqqgtr;", 
+            "description": "Named entity: lesseqqgtr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lessgtr", 
+            "description": "Bad named entity: lessgtr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lessgtr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lessgtr;", 
+            "description": "Named entity: lessgtr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2276"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesssim", 
+            "description": "Bad named entity: lesssim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lesssim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lesssim;", 
+            "description": "Named entity: lesssim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2272"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lfisht", 
+            "description": "Bad named entity: lfisht without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lfisht"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lfisht;", 
+            "description": "Named entity: lfisht; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u297c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lfloor", 
+            "description": "Bad named entity: lfloor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lfloor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lfloor;", 
+            "description": "Named entity: lfloor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lfr", 
+            "description": "Bad named entity: lfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lfr;", 
+            "description": "Named entity: lfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd29"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lg", 
+            "description": "Bad named entity: lg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lg;", 
+            "description": "Named entity: lg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2276"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lgE", 
+            "description": "Bad named entity: lgE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lgE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lgE;", 
+            "description": "Named entity: lgE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a91"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lhard", 
+            "description": "Bad named entity: lhard without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lhard"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lhard;", 
+            "description": "Named entity: lhard; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lharu", 
+            "description": "Bad named entity: lharu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lharu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lharu;", 
+            "description": "Named entity: lharu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lharul", 
+            "description": "Bad named entity: lharul without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lharul"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lharul;", 
+            "description": "Named entity: lharul; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lhblk", 
+            "description": "Bad named entity: lhblk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lhblk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lhblk;", 
+            "description": "Named entity: lhblk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2584"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ljcy", 
+            "description": "Bad named entity: ljcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ljcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ljcy;", 
+            "description": "Named entity: ljcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0459"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ll", 
+            "description": "Bad named entity: ll without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ll"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ll;", 
+            "description": "Named entity: ll; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&llarr", 
+            "description": "Bad named entity: llarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&llarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&llarr;", 
+            "description": "Named entity: llarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&llcorner", 
+            "description": "Bad named entity: llcorner without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&llcorner"
+                ]
+            ]
+        }, 
+        {
+            "input": "&llcorner;", 
+            "description": "Named entity: llcorner; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&llhard", 
+            "description": "Bad named entity: llhard without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&llhard"
+                ]
+            ]
+        }, 
+        {
+            "input": "&llhard;", 
+            "description": "Named entity: llhard; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lltri", 
+            "description": "Bad named entity: lltri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lltri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lltri;", 
+            "description": "Named entity: lltri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25fa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lmidot", 
+            "description": "Bad named entity: lmidot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lmidot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lmidot;", 
+            "description": "Named entity: lmidot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0140"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lmoust", 
+            "description": "Bad named entity: lmoust without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lmoust"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lmoust;", 
+            "description": "Named entity: lmoust; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lmoustache", 
+            "description": "Bad named entity: lmoustache without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lmoustache"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lmoustache;", 
+            "description": "Named entity: lmoustache; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnE", 
+            "description": "Bad named entity: lnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnE;", 
+            "description": "Named entity: lnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2268"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnap", 
+            "description": "Bad named entity: lnap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lnap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnap;", 
+            "description": "Named entity: lnap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a89"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnapprox", 
+            "description": "Bad named entity: lnapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lnapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnapprox;", 
+            "description": "Named entity: lnapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a89"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lne", 
+            "description": "Bad named entity: lne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lne;", 
+            "description": "Named entity: lne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a87"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lneq", 
+            "description": "Bad named entity: lneq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lneq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lneq;", 
+            "description": "Named entity: lneq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a87"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lneqq", 
+            "description": "Bad named entity: lneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lneqq;", 
+            "description": "Named entity: lneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2268"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnsim", 
+            "description": "Bad named entity: lnsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lnsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lnsim;", 
+            "description": "Named entity: lnsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loang", 
+            "description": "Bad named entity: loang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&loang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loang;", 
+            "description": "Named entity: loang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27ec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loarr", 
+            "description": "Bad named entity: loarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&loarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loarr;", 
+            "description": "Named entity: loarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21fd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lobrk", 
+            "description": "Bad named entity: lobrk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lobrk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lobrk;", 
+            "description": "Named entity: lobrk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longleftarrow", 
+            "description": "Bad named entity: longleftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&longleftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longleftarrow;", 
+            "description": "Named entity: longleftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longleftrightarrow", 
+            "description": "Bad named entity: longleftrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&longleftrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longleftrightarrow;", 
+            "description": "Named entity: longleftrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longmapsto", 
+            "description": "Bad named entity: longmapsto without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&longmapsto"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longmapsto;", 
+            "description": "Named entity: longmapsto; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27fc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longrightarrow", 
+            "description": "Bad named entity: longrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&longrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&longrightarrow;", 
+            "description": "Named entity: longrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&looparrowleft", 
+            "description": "Bad named entity: looparrowleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&looparrowleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&looparrowleft;", 
+            "description": "Named entity: looparrowleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ab"
+                ]
+            ]
+        }, 
+        {
+            "input": "&looparrowright", 
+            "description": "Bad named entity: looparrowright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&looparrowright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&looparrowright;", 
+            "description": "Named entity: looparrowright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lopar", 
+            "description": "Bad named entity: lopar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lopar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lopar;", 
+            "description": "Named entity: lopar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2985"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lopf", 
+            "description": "Bad named entity: lopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lopf;", 
+            "description": "Named entity: lopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd5d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loplus", 
+            "description": "Bad named entity: loplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&loplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loplus;", 
+            "description": "Named entity: loplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a2d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lotimes", 
+            "description": "Bad named entity: lotimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lotimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lotimes;", 
+            "description": "Named entity: lotimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a34"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lowast", 
+            "description": "Bad named entity: lowast without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lowast"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lowast;", 
+            "description": "Named entity: lowast; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2217"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lowbar", 
+            "description": "Bad named entity: lowbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lowbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lowbar;", 
+            "description": "Named entity: lowbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "_"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loz", 
+            "description": "Bad named entity: loz without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&loz"
+                ]
+            ]
+        }, 
+        {
+            "input": "&loz;", 
+            "description": "Named entity: loz; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lozenge", 
+            "description": "Bad named entity: lozenge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lozenge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lozenge;", 
+            "description": "Named entity: lozenge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lozf", 
+            "description": "Bad named entity: lozf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lozf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lozf;", 
+            "description": "Named entity: lozf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lpar", 
+            "description": "Bad named entity: lpar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lpar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lpar;", 
+            "description": "Named entity: lpar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "("
+                ]
+            ]
+        }, 
+        {
+            "input": "&lparlt", 
+            "description": "Bad named entity: lparlt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lparlt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lparlt;", 
+            "description": "Named entity: lparlt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2993"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrarr", 
+            "description": "Bad named entity: lrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrarr;", 
+            "description": "Named entity: lrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrcorner", 
+            "description": "Bad named entity: lrcorner without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lrcorner"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrcorner;", 
+            "description": "Named entity: lrcorner; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrhar", 
+            "description": "Bad named entity: lrhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lrhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrhar;", 
+            "description": "Named entity: lrhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrhard", 
+            "description": "Bad named entity: lrhard without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lrhard"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrhard;", 
+            "description": "Named entity: lrhard; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrm", 
+            "description": "Bad named entity: lrm without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lrm"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrm;", 
+            "description": "Named entity: lrm; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrtri", 
+            "description": "Bad named entity: lrtri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lrtri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lrtri;", 
+            "description": "Named entity: lrtri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsaquo", 
+            "description": "Bad named entity: lsaquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsaquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsaquo;", 
+            "description": "Named entity: lsaquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2039"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lscr", 
+            "description": "Bad named entity: lscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lscr;", 
+            "description": "Named entity: lscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsh", 
+            "description": "Bad named entity: lsh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsh;", 
+            "description": "Named entity: lsh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsim", 
+            "description": "Bad named entity: lsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsim;", 
+            "description": "Named entity: lsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2272"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsime", 
+            "description": "Bad named entity: lsime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsime;", 
+            "description": "Named entity: lsime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsimg", 
+            "description": "Bad named entity: lsimg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsimg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsimg;", 
+            "description": "Named entity: lsimg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a8f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsqb", 
+            "description": "Bad named entity: lsqb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsqb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsqb;", 
+            "description": "Named entity: lsqb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "["
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsquo", 
+            "description": "Bad named entity: lsquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsquo;", 
+            "description": "Named entity: lsquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2018"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsquor", 
+            "description": "Bad named entity: lsquor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lsquor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lsquor;", 
+            "description": "Named entity: lsquor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lstrok", 
+            "description": "Bad named entity: lstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lstrok;", 
+            "description": "Named entity: lstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0142"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lt", 
+            "description": "Named entity: lt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "<"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lt;", 
+            "description": "Named entity: lt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "<"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltcc;", 
+            "description": "Named entity: ltcc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltcir;", 
+            "description": "Named entity: ltcir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a79"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltdot;", 
+            "description": "Named entity: ltdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lthree;", 
+            "description": "Named entity: lthree; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltimes;", 
+            "description": "Named entity: ltimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltlarr;", 
+            "description": "Named entity: ltlarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2976"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltquest;", 
+            "description": "Named entity: ltquest; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltrPar;", 
+            "description": "Named entity: ltrPar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2996"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltri;", 
+            "description": "Named entity: ltri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltrie;", 
+            "description": "Named entity: ltrie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ltrif;", 
+            "description": "Named entity: ltrif; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lurdshar", 
+            "description": "Bad named entity: lurdshar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lurdshar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lurdshar;", 
+            "description": "Named entity: lurdshar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u294a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&luruhar", 
+            "description": "Bad named entity: luruhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&luruhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&luruhar;", 
+            "description": "Named entity: luruhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2966"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lvertneqq", 
+            "description": "Bad named entity: lvertneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lvertneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lvertneqq;", 
+            "description": "Named entity: lvertneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2268\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lvnE", 
+            "description": "Bad named entity: lvnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&lvnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&lvnE;", 
+            "description": "Named entity: lvnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2268\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mDDot", 
+            "description": "Bad named entity: mDDot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mDDot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mDDot;", 
+            "description": "Named entity: mDDot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&macr", 
+            "description": "Named entity: macr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00af"
+                ]
+            ]
+        }, 
+        {
+            "input": "&macr;", 
+            "description": "Named entity: macr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00af"
+                ]
+            ]
+        }, 
+        {
+            "input": "&male", 
+            "description": "Bad named entity: male without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&male"
+                ]
+            ]
+        }, 
+        {
+            "input": "&male;", 
+            "description": "Named entity: male; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2642"
+                ]
+            ]
+        }, 
+        {
+            "input": "&malt", 
+            "description": "Bad named entity: malt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&malt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&malt;", 
+            "description": "Named entity: malt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2720"
+                ]
+            ]
+        }, 
+        {
+            "input": "&maltese", 
+            "description": "Bad named entity: maltese without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&maltese"
+                ]
+            ]
+        }, 
+        {
+            "input": "&maltese;", 
+            "description": "Named entity: maltese; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2720"
+                ]
+            ]
+        }, 
+        {
+            "input": "&map", 
+            "description": "Bad named entity: map without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&map"
+                ]
+            ]
+        }, 
+        {
+            "input": "&map;", 
+            "description": "Named entity: map; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapsto", 
+            "description": "Bad named entity: mapsto without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mapsto"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapsto;", 
+            "description": "Named entity: mapsto; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapstodown", 
+            "description": "Bad named entity: mapstodown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mapstodown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapstodown;", 
+            "description": "Named entity: mapstodown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapstoleft", 
+            "description": "Bad named entity: mapstoleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mapstoleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapstoleft;", 
+            "description": "Named entity: mapstoleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapstoup", 
+            "description": "Bad named entity: mapstoup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mapstoup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mapstoup;", 
+            "description": "Named entity: mapstoup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&marker", 
+            "description": "Bad named entity: marker without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&marker"
+                ]
+            ]
+        }, 
+        {
+            "input": "&marker;", 
+            "description": "Named entity: marker; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mcomma", 
+            "description": "Bad named entity: mcomma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mcomma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mcomma;", 
+            "description": "Named entity: mcomma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a29"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mcy", 
+            "description": "Bad named entity: mcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mcy;", 
+            "description": "Named entity: mcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u043c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mdash", 
+            "description": "Bad named entity: mdash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mdash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mdash;", 
+            "description": "Named entity: mdash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2014"
+                ]
+            ]
+        }, 
+        {
+            "input": "&measuredangle", 
+            "description": "Bad named entity: measuredangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&measuredangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&measuredangle;", 
+            "description": "Named entity: measuredangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2221"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mfr", 
+            "description": "Bad named entity: mfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mfr;", 
+            "description": "Named entity: mfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd2a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mho", 
+            "description": "Bad named entity: mho without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mho"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mho;", 
+            "description": "Named entity: mho; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2127"
+                ]
+            ]
+        }, 
+        {
+            "input": "&micro", 
+            "description": "Named entity: micro without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&micro;", 
+            "description": "Named entity: micro; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mid", 
+            "description": "Bad named entity: mid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mid;", 
+            "description": "Named entity: mid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2223"
+                ]
+            ]
+        }, 
+        {
+            "input": "&midast", 
+            "description": "Bad named entity: midast without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&midast"
+                ]
+            ]
+        }, 
+        {
+            "input": "&midast;", 
+            "description": "Named entity: midast; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "*"
+                ]
+            ]
+        }, 
+        {
+            "input": "&midcir", 
+            "description": "Bad named entity: midcir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&midcir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&midcir;", 
+            "description": "Named entity: midcir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2af0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&middot", 
+            "description": "Named entity: middot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&middot;", 
+            "description": "Named entity: middot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minus", 
+            "description": "Bad named entity: minus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&minus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minus;", 
+            "description": "Named entity: minus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2212"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minusb", 
+            "description": "Bad named entity: minusb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&minusb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minusb;", 
+            "description": "Named entity: minusb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minusd", 
+            "description": "Bad named entity: minusd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&minusd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minusd;", 
+            "description": "Named entity: minusd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2238"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minusdu", 
+            "description": "Bad named entity: minusdu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&minusdu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&minusdu;", 
+            "description": "Named entity: minusdu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a2a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mlcp", 
+            "description": "Bad named entity: mlcp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mlcp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mlcp;", 
+            "description": "Named entity: mlcp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2adb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mldr", 
+            "description": "Bad named entity: mldr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mldr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mldr;", 
+            "description": "Named entity: mldr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2026"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mnplus", 
+            "description": "Bad named entity: mnplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mnplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mnplus;", 
+            "description": "Named entity: mnplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2213"
+                ]
+            ]
+        }, 
+        {
+            "input": "&models", 
+            "description": "Bad named entity: models without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&models"
+                ]
+            ]
+        }, 
+        {
+            "input": "&models;", 
+            "description": "Named entity: models; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mopf", 
+            "description": "Bad named entity: mopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mopf;", 
+            "description": "Named entity: mopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd5e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mp", 
+            "description": "Bad named entity: mp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mp;", 
+            "description": "Named entity: mp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2213"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mscr", 
+            "description": "Bad named entity: mscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mscr;", 
+            "description": "Named entity: mscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mstpos", 
+            "description": "Bad named entity: mstpos without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mstpos"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mstpos;", 
+            "description": "Named entity: mstpos; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mu", 
+            "description": "Bad named entity: mu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mu;", 
+            "description": "Named entity: mu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03bc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&multimap", 
+            "description": "Bad named entity: multimap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&multimap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&multimap;", 
+            "description": "Named entity: multimap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mumap", 
+            "description": "Bad named entity: mumap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&mumap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&mumap;", 
+            "description": "Named entity: mumap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nGg", 
+            "description": "Bad named entity: nGg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nGg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nGg;", 
+            "description": "Named entity: nGg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d9\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nGt", 
+            "description": "Bad named entity: nGt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nGt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nGt;", 
+            "description": "Named entity: nGt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226b\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nGtv", 
+            "description": "Bad named entity: nGtv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nGtv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nGtv;", 
+            "description": "Named entity: nGtv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226b\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLeftarrow", 
+            "description": "Bad named entity: nLeftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nLeftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLeftarrow;", 
+            "description": "Named entity: nLeftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLeftrightarrow", 
+            "description": "Bad named entity: nLeftrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nLeftrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLeftrightarrow;", 
+            "description": "Named entity: nLeftrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLl", 
+            "description": "Bad named entity: nLl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nLl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLl;", 
+            "description": "Named entity: nLl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d8\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLt", 
+            "description": "Bad named entity: nLt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nLt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLt;", 
+            "description": "Named entity: nLt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226a\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLtv", 
+            "description": "Bad named entity: nLtv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nLtv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nLtv;", 
+            "description": "Named entity: nLtv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226a\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nRightarrow", 
+            "description": "Bad named entity: nRightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nRightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nRightarrow;", 
+            "description": "Named entity: nRightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nVDash", 
+            "description": "Bad named entity: nVDash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nVDash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nVDash;", 
+            "description": "Named entity: nVDash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22af"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nVdash", 
+            "description": "Bad named entity: nVdash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nVdash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nVdash;", 
+            "description": "Named entity: nVdash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nabla", 
+            "description": "Bad named entity: nabla without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nabla"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nabla;", 
+            "description": "Named entity: nabla; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2207"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nacute", 
+            "description": "Bad named entity: nacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nacute;", 
+            "description": "Named entity: nacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0144"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nang", 
+            "description": "Bad named entity: nang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nang;", 
+            "description": "Named entity: nang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2220\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nap", 
+            "description": "Bad named entity: nap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nap;", 
+            "description": "Named entity: nap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2249"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napE", 
+            "description": "Bad named entity: napE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&napE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napE;", 
+            "description": "Named entity: napE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a70\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napid", 
+            "description": "Bad named entity: napid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&napid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napid;", 
+            "description": "Named entity: napid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224b\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napos", 
+            "description": "Bad named entity: napos without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&napos"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napos;", 
+            "description": "Named entity: napos; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0149"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napprox", 
+            "description": "Bad named entity: napprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&napprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&napprox;", 
+            "description": "Named entity: napprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2249"
+                ]
+            ]
+        }, 
+        {
+            "input": "&natur", 
+            "description": "Bad named entity: natur without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&natur"
+                ]
+            ]
+        }, 
+        {
+            "input": "&natur;", 
+            "description": "Named entity: natur; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u266e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&natural", 
+            "description": "Bad named entity: natural without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&natural"
+                ]
+            ]
+        }, 
+        {
+            "input": "&natural;", 
+            "description": "Named entity: natural; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u266e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&naturals", 
+            "description": "Bad named entity: naturals without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&naturals"
+                ]
+            ]
+        }, 
+        {
+            "input": "&naturals;", 
+            "description": "Named entity: naturals; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2115"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nbsp", 
+            "description": "Named entity: nbsp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nbsp;", 
+            "description": "Named entity: nbsp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nbump", 
+            "description": "Bad named entity: nbump without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nbump"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nbump;", 
+            "description": "Named entity: nbump; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224e\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nbumpe", 
+            "description": "Bad named entity: nbumpe without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nbumpe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nbumpe;", 
+            "description": "Named entity: nbumpe; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224f\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncap", 
+            "description": "Bad named entity: ncap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ncap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncap;", 
+            "description": "Named entity: ncap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a43"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncaron", 
+            "description": "Bad named entity: ncaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ncaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncaron;", 
+            "description": "Named entity: ncaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0148"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncedil", 
+            "description": "Bad named entity: ncedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ncedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncedil;", 
+            "description": "Named entity: ncedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0146"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncong", 
+            "description": "Bad named entity: ncong without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ncong"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncong;", 
+            "description": "Named entity: ncong; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2247"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncongdot", 
+            "description": "Bad named entity: ncongdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ncongdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncongdot;", 
+            "description": "Named entity: ncongdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a6d\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncup", 
+            "description": "Bad named entity: ncup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ncup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncup;", 
+            "description": "Named entity: ncup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a42"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncy", 
+            "description": "Bad named entity: ncy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ncy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ncy;", 
+            "description": "Named entity: ncy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u043d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ndash", 
+            "description": "Bad named entity: ndash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ndash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ndash;", 
+            "description": "Named entity: ndash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2013"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ne", 
+            "description": "Bad named entity: ne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ne;", 
+            "description": "Named entity: ne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2260"
+                ]
+            ]
+        }, 
+        {
+            "input": "&neArr", 
+            "description": "Bad named entity: neArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&neArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&neArr;", 
+            "description": "Named entity: neArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nearhk", 
+            "description": "Bad named entity: nearhk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nearhk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nearhk;", 
+            "description": "Named entity: nearhk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2924"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nearr", 
+            "description": "Bad named entity: nearr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nearr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nearr;", 
+            "description": "Named entity: nearr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2197"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nearrow", 
+            "description": "Bad named entity: nearrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nearrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nearrow;", 
+            "description": "Named entity: nearrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2197"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nedot", 
+            "description": "Bad named entity: nedot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nedot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nedot;", 
+            "description": "Named entity: nedot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2250\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nequiv", 
+            "description": "Bad named entity: nequiv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nequiv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nequiv;", 
+            "description": "Named entity: nequiv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2262"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nesear", 
+            "description": "Bad named entity: nesear without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nesear"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nesear;", 
+            "description": "Named entity: nesear; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2928"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nesim", 
+            "description": "Bad named entity: nesim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nesim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nesim;", 
+            "description": "Named entity: nesim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2242\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nexist", 
+            "description": "Bad named entity: nexist without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nexist"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nexist;", 
+            "description": "Named entity: nexist; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2204"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nexists", 
+            "description": "Bad named entity: nexists without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nexists"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nexists;", 
+            "description": "Named entity: nexists; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2204"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nfr", 
+            "description": "Bad named entity: nfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nfr;", 
+            "description": "Named entity: nfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd2b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngE", 
+            "description": "Bad named entity: ngE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ngE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngE;", 
+            "description": "Named entity: ngE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2267\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nge", 
+            "description": "Bad named entity: nge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nge;", 
+            "description": "Named entity: nge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2271"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngeq", 
+            "description": "Bad named entity: ngeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ngeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngeq;", 
+            "description": "Named entity: ngeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2271"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngeqq", 
+            "description": "Bad named entity: ngeqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ngeqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngeqq;", 
+            "description": "Named entity: ngeqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2267\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngeqslant", 
+            "description": "Bad named entity: ngeqslant without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ngeqslant"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngeqslant;", 
+            "description": "Named entity: ngeqslant; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7e\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nges", 
+            "description": "Bad named entity: nges without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nges"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nges;", 
+            "description": "Named entity: nges; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7e\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngsim", 
+            "description": "Bad named entity: ngsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ngsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngsim;", 
+            "description": "Named entity: ngsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2275"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngt", 
+            "description": "Bad named entity: ngt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ngt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngt;", 
+            "description": "Named entity: ngt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngtr", 
+            "description": "Bad named entity: ngtr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ngtr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ngtr;", 
+            "description": "Named entity: ngtr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nhArr", 
+            "description": "Bad named entity: nhArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nhArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nhArr;", 
+            "description": "Named entity: nhArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nharr", 
+            "description": "Bad named entity: nharr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nharr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nharr;", 
+            "description": "Named entity: nharr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nhpar", 
+            "description": "Bad named entity: nhpar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nhpar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nhpar;", 
+            "description": "Named entity: nhpar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2af2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ni", 
+            "description": "Bad named entity: ni without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ni"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ni;", 
+            "description": "Named entity: ni; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nis", 
+            "description": "Bad named entity: nis without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nis"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nis;", 
+            "description": "Named entity: nis; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22fc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nisd", 
+            "description": "Bad named entity: nisd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nisd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nisd;", 
+            "description": "Named entity: nisd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22fa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&niv", 
+            "description": "Bad named entity: niv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&niv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&niv;", 
+            "description": "Named entity: niv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&njcy", 
+            "description": "Bad named entity: njcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&njcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&njcy;", 
+            "description": "Named entity: njcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u045a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlArr", 
+            "description": "Bad named entity: nlArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nlArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlArr;", 
+            "description": "Named entity: nlArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlE", 
+            "description": "Bad named entity: nlE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nlE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlE;", 
+            "description": "Named entity: nlE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2266\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlarr", 
+            "description": "Bad named entity: nlarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nlarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlarr;", 
+            "description": "Named entity: nlarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nldr", 
+            "description": "Bad named entity: nldr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nldr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nldr;", 
+            "description": "Named entity: nldr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2025"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nle", 
+            "description": "Bad named entity: nle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nle;", 
+            "description": "Named entity: nle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2270"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleftarrow", 
+            "description": "Bad named entity: nleftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nleftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleftarrow;", 
+            "description": "Named entity: nleftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleftrightarrow", 
+            "description": "Bad named entity: nleftrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nleftrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleftrightarrow;", 
+            "description": "Named entity: nleftrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleq", 
+            "description": "Bad named entity: nleq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nleq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleq;", 
+            "description": "Named entity: nleq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2270"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleqq", 
+            "description": "Bad named entity: nleqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nleqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleqq;", 
+            "description": "Named entity: nleqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2266\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleqslant", 
+            "description": "Bad named entity: nleqslant without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nleqslant"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nleqslant;", 
+            "description": "Named entity: nleqslant; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7d\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nles", 
+            "description": "Bad named entity: nles without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nles"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nles;", 
+            "description": "Named entity: nles; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a7d\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nless", 
+            "description": "Bad named entity: nless without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nless"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nless;", 
+            "description": "Named entity: nless; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlsim", 
+            "description": "Bad named entity: nlsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nlsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlsim;", 
+            "description": "Named entity: nlsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2274"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlt", 
+            "description": "Bad named entity: nlt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nlt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nlt;", 
+            "description": "Named entity: nlt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nltri", 
+            "description": "Bad named entity: nltri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nltri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nltri;", 
+            "description": "Named entity: nltri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ea"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nltrie", 
+            "description": "Bad named entity: nltrie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nltrie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nltrie;", 
+            "description": "Named entity: nltrie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nmid", 
+            "description": "Bad named entity: nmid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nmid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nmid;", 
+            "description": "Named entity: nmid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2224"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nopf", 
+            "description": "Bad named entity: nopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nopf;", 
+            "description": "Named entity: nopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd5f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&not", 
+            "description": "Named entity: not without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&not;", 
+            "description": "Named entity: not; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notin;", 
+            "description": "Named entity: notin; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2209"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notinE;", 
+            "description": "Named entity: notinE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f9\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notindot;", 
+            "description": "Named entity: notindot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f5\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notinva;", 
+            "description": "Named entity: notinva; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2209"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notinvb;", 
+            "description": "Named entity: notinvb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notinvc;", 
+            "description": "Named entity: notinvc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notni;", 
+            "description": "Named entity: notni; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notniva;", 
+            "description": "Named entity: notniva; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notnivb;", 
+            "description": "Named entity: notnivb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22fe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&notnivc;", 
+            "description": "Named entity: notnivc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22fd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npar", 
+            "description": "Bad named entity: npar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&npar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npar;", 
+            "description": "Named entity: npar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2226"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nparallel", 
+            "description": "Bad named entity: nparallel without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nparallel"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nparallel;", 
+            "description": "Named entity: nparallel; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2226"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nparsl", 
+            "description": "Bad named entity: nparsl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nparsl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nparsl;", 
+            "description": "Named entity: nparsl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2afd\u20e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npart", 
+            "description": "Bad named entity: npart without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&npart"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npart;", 
+            "description": "Named entity: npart; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2202\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npolint", 
+            "description": "Bad named entity: npolint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&npolint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npolint;", 
+            "description": "Named entity: npolint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a14"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npr", 
+            "description": "Bad named entity: npr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&npr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npr;", 
+            "description": "Named entity: npr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2280"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nprcue", 
+            "description": "Bad named entity: nprcue without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nprcue"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nprcue;", 
+            "description": "Named entity: nprcue; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npre", 
+            "description": "Bad named entity: npre without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&npre"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npre;", 
+            "description": "Named entity: npre; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aaf\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nprec", 
+            "description": "Bad named entity: nprec without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nprec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nprec;", 
+            "description": "Named entity: nprec; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2280"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npreceq", 
+            "description": "Bad named entity: npreceq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&npreceq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&npreceq;", 
+            "description": "Named entity: npreceq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aaf\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrArr", 
+            "description": "Bad named entity: nrArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nrArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrArr;", 
+            "description": "Named entity: nrArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrarr", 
+            "description": "Bad named entity: nrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrarr;", 
+            "description": "Named entity: nrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrarrc", 
+            "description": "Bad named entity: nrarrc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nrarrc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrarrc;", 
+            "description": "Named entity: nrarrc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2933\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrarrw", 
+            "description": "Bad named entity: nrarrw without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nrarrw"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrarrw;", 
+            "description": "Named entity: nrarrw; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219d\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrightarrow", 
+            "description": "Bad named entity: nrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrightarrow;", 
+            "description": "Named entity: nrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrtri", 
+            "description": "Bad named entity: nrtri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nrtri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrtri;", 
+            "description": "Named entity: nrtri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrtrie", 
+            "description": "Bad named entity: nrtrie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nrtrie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nrtrie;", 
+            "description": "Named entity: nrtrie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsc", 
+            "description": "Bad named entity: nsc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsc;", 
+            "description": "Named entity: nsc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2281"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsccue", 
+            "description": "Bad named entity: nsccue without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsccue"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsccue;", 
+            "description": "Named entity: nsccue; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsce", 
+            "description": "Bad named entity: nsce without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsce;", 
+            "description": "Named entity: nsce; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab0\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nscr", 
+            "description": "Bad named entity: nscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nscr;", 
+            "description": "Named entity: nscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nshortmid", 
+            "description": "Bad named entity: nshortmid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nshortmid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nshortmid;", 
+            "description": "Named entity: nshortmid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2224"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nshortparallel", 
+            "description": "Bad named entity: nshortparallel without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nshortparallel"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nshortparallel;", 
+            "description": "Named entity: nshortparallel; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2226"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsim", 
+            "description": "Bad named entity: nsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsim;", 
+            "description": "Named entity: nsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2241"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsime", 
+            "description": "Bad named entity: nsime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsime;", 
+            "description": "Named entity: nsime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2244"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsimeq", 
+            "description": "Bad named entity: nsimeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsimeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsimeq;", 
+            "description": "Named entity: nsimeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2244"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsmid", 
+            "description": "Bad named entity: nsmid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsmid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsmid;", 
+            "description": "Named entity: nsmid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2224"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nspar", 
+            "description": "Bad named entity: nspar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nspar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nspar;", 
+            "description": "Named entity: nspar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2226"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsqsube", 
+            "description": "Bad named entity: nsqsube without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsqsube"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsqsube;", 
+            "description": "Named entity: nsqsube; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsqsupe", 
+            "description": "Bad named entity: nsqsupe without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsqsupe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsqsupe;", 
+            "description": "Named entity: nsqsupe; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsub", 
+            "description": "Bad named entity: nsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsub;", 
+            "description": "Named entity: nsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2284"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubE", 
+            "description": "Bad named entity: nsubE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsubE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubE;", 
+            "description": "Named entity: nsubE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac5\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsube", 
+            "description": "Bad named entity: nsube without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsube"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsube;", 
+            "description": "Named entity: nsube; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2288"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubset", 
+            "description": "Bad named entity: nsubset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsubset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubset;", 
+            "description": "Named entity: nsubset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2282\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubseteq", 
+            "description": "Bad named entity: nsubseteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsubseteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubseteq;", 
+            "description": "Named entity: nsubseteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2288"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubseteqq", 
+            "description": "Bad named entity: nsubseteqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsubseteqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsubseteqq;", 
+            "description": "Named entity: nsubseteqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac5\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsucc", 
+            "description": "Bad named entity: nsucc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsucc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsucc;", 
+            "description": "Named entity: nsucc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2281"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsucceq", 
+            "description": "Bad named entity: nsucceq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsucceq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsucceq;", 
+            "description": "Named entity: nsucceq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab0\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsup", 
+            "description": "Bad named entity: nsup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsup;", 
+            "description": "Named entity: nsup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2285"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupE", 
+            "description": "Bad named entity: nsupE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsupE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupE;", 
+            "description": "Named entity: nsupE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac6\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupe", 
+            "description": "Bad named entity: nsupe without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsupe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupe;", 
+            "description": "Named entity: nsupe; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2289"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupset", 
+            "description": "Bad named entity: nsupset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsupset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupset;", 
+            "description": "Named entity: nsupset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2283\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupseteq", 
+            "description": "Bad named entity: nsupseteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsupseteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupseteq;", 
+            "description": "Named entity: nsupseteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2289"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupseteqq", 
+            "description": "Bad named entity: nsupseteqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nsupseteqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nsupseteqq;", 
+            "description": "Named entity: nsupseteqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac6\u0338"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntgl", 
+            "description": "Bad named entity: ntgl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ntgl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntgl;", 
+            "description": "Named entity: ntgl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2279"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntilde", 
+            "description": "Named entity: ntilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntilde;", 
+            "description": "Named entity: ntilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntlg", 
+            "description": "Bad named entity: ntlg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ntlg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntlg;", 
+            "description": "Named entity: ntlg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2278"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntriangleleft", 
+            "description": "Bad named entity: ntriangleleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ntriangleleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntriangleleft;", 
+            "description": "Named entity: ntriangleleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ea"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntrianglelefteq", 
+            "description": "Bad named entity: ntrianglelefteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ntrianglelefteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntrianglelefteq;", 
+            "description": "Named entity: ntrianglelefteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntriangleright", 
+            "description": "Bad named entity: ntriangleright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ntriangleright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntriangleright;", 
+            "description": "Named entity: ntriangleright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22eb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntrianglerighteq", 
+            "description": "Bad named entity: ntrianglerighteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ntrianglerighteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ntrianglerighteq;", 
+            "description": "Named entity: ntrianglerighteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nu", 
+            "description": "Bad named entity: nu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nu;", 
+            "description": "Named entity: nu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&num", 
+            "description": "Bad named entity: num without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&num"
+                ]
+            ]
+        }, 
+        {
+            "input": "&num;", 
+            "description": "Named entity: num; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "#"
+                ]
+            ]
+        }, 
+        {
+            "input": "&numero", 
+            "description": "Bad named entity: numero without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&numero"
+                ]
+            ]
+        }, 
+        {
+            "input": "&numero;", 
+            "description": "Named entity: numero; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2116"
+                ]
+            ]
+        }, 
+        {
+            "input": "&numsp", 
+            "description": "Bad named entity: numsp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&numsp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&numsp;", 
+            "description": "Named entity: numsp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2007"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvDash", 
+            "description": "Bad named entity: nvDash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvDash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvDash;", 
+            "description": "Named entity: nvDash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvHarr", 
+            "description": "Bad named entity: nvHarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvHarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvHarr;", 
+            "description": "Named entity: nvHarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2904"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvap", 
+            "description": "Bad named entity: nvap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvap;", 
+            "description": "Named entity: nvap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u224d\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvdash", 
+            "description": "Bad named entity: nvdash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvdash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvdash;", 
+            "description": "Named entity: nvdash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvge", 
+            "description": "Bad named entity: nvge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvge;", 
+            "description": "Named entity: nvge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2265\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvgt", 
+            "description": "Bad named entity: nvgt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvgt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvgt;", 
+            "description": "Named entity: nvgt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    ">\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvinfin", 
+            "description": "Bad named entity: nvinfin without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvinfin"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvinfin;", 
+            "description": "Named entity: nvinfin; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29de"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvlArr", 
+            "description": "Bad named entity: nvlArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvlArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvlArr;", 
+            "description": "Named entity: nvlArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2902"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvle", 
+            "description": "Bad named entity: nvle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvle;", 
+            "description": "Named entity: nvle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2264\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvlt", 
+            "description": "Bad named entity: nvlt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvlt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvlt;", 
+            "description": "Named entity: nvlt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "<\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvltrie", 
+            "description": "Bad named entity: nvltrie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvltrie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvltrie;", 
+            "description": "Named entity: nvltrie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b4\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvrArr", 
+            "description": "Bad named entity: nvrArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvrArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvrArr;", 
+            "description": "Named entity: nvrArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2903"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvrtrie", 
+            "description": "Bad named entity: nvrtrie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvrtrie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvrtrie;", 
+            "description": "Named entity: nvrtrie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b5\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvsim", 
+            "description": "Bad named entity: nvsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nvsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nvsim;", 
+            "description": "Named entity: nvsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223c\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwArr", 
+            "description": "Bad named entity: nwArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nwArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwArr;", 
+            "description": "Named entity: nwArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwarhk", 
+            "description": "Bad named entity: nwarhk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nwarhk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwarhk;", 
+            "description": "Named entity: nwarhk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2923"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwarr", 
+            "description": "Bad named entity: nwarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nwarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwarr;", 
+            "description": "Named entity: nwarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2196"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwarrow", 
+            "description": "Bad named entity: nwarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nwarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwarrow;", 
+            "description": "Named entity: nwarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2196"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwnear", 
+            "description": "Bad named entity: nwnear without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&nwnear"
+                ]
+            ]
+        }, 
+        {
+            "input": "&nwnear;", 
+            "description": "Named entity: nwnear; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2927"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oS", 
+            "description": "Bad named entity: oS without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oS"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oS;", 
+            "description": "Named entity: oS; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u24c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oacute", 
+            "description": "Named entity: oacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oacute;", 
+            "description": "Named entity: oacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oast", 
+            "description": "Bad named entity: oast without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oast"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oast;", 
+            "description": "Named entity: oast; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ocir", 
+            "description": "Bad named entity: ocir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ocir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ocir;", 
+            "description": "Named entity: ocir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ocirc", 
+            "description": "Named entity: ocirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ocirc;", 
+            "description": "Named entity: ocirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ocy", 
+            "description": "Bad named entity: ocy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ocy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ocy;", 
+            "description": "Named entity: ocy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u043e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odash", 
+            "description": "Bad named entity: odash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&odash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odash;", 
+            "description": "Named entity: odash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odblac", 
+            "description": "Bad named entity: odblac without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&odblac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odblac;", 
+            "description": "Named entity: odblac; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0151"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odiv", 
+            "description": "Bad named entity: odiv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&odiv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odiv;", 
+            "description": "Named entity: odiv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a38"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odot", 
+            "description": "Bad named entity: odot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&odot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odot;", 
+            "description": "Named entity: odot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2299"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odsold", 
+            "description": "Bad named entity: odsold without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&odsold"
+                ]
+            ]
+        }, 
+        {
+            "input": "&odsold;", 
+            "description": "Named entity: odsold; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29bc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oelig", 
+            "description": "Bad named entity: oelig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oelig"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oelig;", 
+            "description": "Named entity: oelig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0153"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ofcir", 
+            "description": "Bad named entity: ofcir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ofcir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ofcir;", 
+            "description": "Named entity: ofcir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ofr", 
+            "description": "Bad named entity: ofr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ofr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ofr;", 
+            "description": "Named entity: ofr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd2c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ogon", 
+            "description": "Bad named entity: ogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ogon;", 
+            "description": "Named entity: ogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ograve", 
+            "description": "Named entity: ograve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ograve;", 
+            "description": "Named entity: ograve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ogt", 
+            "description": "Bad named entity: ogt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ogt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ogt;", 
+            "description": "Named entity: ogt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ohbar", 
+            "description": "Bad named entity: ohbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ohbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ohbar;", 
+            "description": "Named entity: ohbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ohm", 
+            "description": "Bad named entity: ohm without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ohm"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ohm;", 
+            "description": "Named entity: ohm; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03a9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oint", 
+            "description": "Bad named entity: oint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oint;", 
+            "description": "Named entity: oint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olarr", 
+            "description": "Bad named entity: olarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&olarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olarr;", 
+            "description": "Named entity: olarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olcir", 
+            "description": "Bad named entity: olcir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&olcir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olcir;", 
+            "description": "Named entity: olcir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olcross", 
+            "description": "Bad named entity: olcross without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&olcross"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olcross;", 
+            "description": "Named entity: olcross; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29bb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oline", 
+            "description": "Bad named entity: oline without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oline"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oline;", 
+            "description": "Named entity: oline; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u203e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olt", 
+            "description": "Bad named entity: olt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&olt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&olt;", 
+            "description": "Named entity: olt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omacr", 
+            "description": "Bad named entity: omacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&omacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omacr;", 
+            "description": "Named entity: omacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u014d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omega", 
+            "description": "Bad named entity: omega without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&omega"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omega;", 
+            "description": "Named entity: omega; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omicron", 
+            "description": "Bad named entity: omicron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&omicron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omicron;", 
+            "description": "Named entity: omicron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omid", 
+            "description": "Bad named entity: omid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&omid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&omid;", 
+            "description": "Named entity: omid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ominus", 
+            "description": "Bad named entity: ominus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ominus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ominus;", 
+            "description": "Named entity: ominus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2296"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oopf", 
+            "description": "Bad named entity: oopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oopf;", 
+            "description": "Named entity: oopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd60"
+                ]
+            ]
+        }, 
+        {
+            "input": "&opar", 
+            "description": "Bad named entity: opar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&opar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&opar;", 
+            "description": "Named entity: opar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&operp", 
+            "description": "Bad named entity: operp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&operp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&operp;", 
+            "description": "Named entity: operp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oplus", 
+            "description": "Bad named entity: oplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oplus;", 
+            "description": "Named entity: oplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2295"
+                ]
+            ]
+        }, 
+        {
+            "input": "&or", 
+            "description": "Bad named entity: or without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&or"
+                ]
+            ]
+        }, 
+        {
+            "input": "&or;", 
+            "description": "Named entity: or; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2228"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orarr", 
+            "description": "Bad named entity: orarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&orarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orarr;", 
+            "description": "Named entity: orarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ord", 
+            "description": "Bad named entity: ord without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ord"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ord;", 
+            "description": "Named entity: ord; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a5d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&order", 
+            "description": "Bad named entity: order without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&order"
+                ]
+            ]
+        }, 
+        {
+            "input": "&order;", 
+            "description": "Named entity: order; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2134"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orderof", 
+            "description": "Bad named entity: orderof without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&orderof"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orderof;", 
+            "description": "Named entity: orderof; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2134"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ordf", 
+            "description": "Named entity: ordf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ordf;", 
+            "description": "Named entity: ordf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ordm", 
+            "description": "Named entity: ordm without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ordm;", 
+            "description": "Named entity: ordm; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&origof", 
+            "description": "Bad named entity: origof without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&origof"
+                ]
+            ]
+        }, 
+        {
+            "input": "&origof;", 
+            "description": "Named entity: origof; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oror", 
+            "description": "Bad named entity: oror without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oror"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oror;", 
+            "description": "Named entity: oror; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a56"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orslope", 
+            "description": "Bad named entity: orslope without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&orslope"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orslope;", 
+            "description": "Named entity: orslope; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a57"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orv", 
+            "description": "Bad named entity: orv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&orv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&orv;", 
+            "description": "Named entity: orv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a5b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oscr", 
+            "description": "Bad named entity: oscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&oscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oscr;", 
+            "description": "Named entity: oscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2134"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oslash", 
+            "description": "Named entity: oslash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&oslash;", 
+            "description": "Named entity: oslash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&osol", 
+            "description": "Bad named entity: osol without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&osol"
+                ]
+            ]
+        }, 
+        {
+            "input": "&osol;", 
+            "description": "Named entity: osol; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2298"
+                ]
+            ]
+        }, 
+        {
+            "input": "&otilde", 
+            "description": "Named entity: otilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&otilde;", 
+            "description": "Named entity: otilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&otimes", 
+            "description": "Bad named entity: otimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&otimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&otimes;", 
+            "description": "Named entity: otimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2297"
+                ]
+            ]
+        }, 
+        {
+            "input": "&otimesas", 
+            "description": "Bad named entity: otimesas without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&otimesas"
+                ]
+            ]
+        }, 
+        {
+            "input": "&otimesas;", 
+            "description": "Named entity: otimesas; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a36"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ouml", 
+            "description": "Named entity: ouml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ouml;", 
+            "description": "Named entity: ouml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ovbar", 
+            "description": "Bad named entity: ovbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ovbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ovbar;", 
+            "description": "Named entity: ovbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u233d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&par", 
+            "description": "Bad named entity: par without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&par"
+                ]
+            ]
+        }, 
+        {
+            "input": "&par;", 
+            "description": "Named entity: par; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2225"
+                ]
+            ]
+        }, 
+        {
+            "input": "&para", 
+            "description": "Named entity: para without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&para;", 
+            "description": "Named entity: para; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&parallel;", 
+            "description": "Named entity: parallel; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2225"
+                ]
+            ]
+        }, 
+        {
+            "input": "&parsim", 
+            "description": "Bad named entity: parsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&parsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&parsim;", 
+            "description": "Named entity: parsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2af3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&parsl", 
+            "description": "Bad named entity: parsl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&parsl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&parsl;", 
+            "description": "Named entity: parsl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2afd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&part", 
+            "description": "Bad named entity: part without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&part"
+                ]
+            ]
+        }, 
+        {
+            "input": "&part;", 
+            "description": "Named entity: part; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2202"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pcy", 
+            "description": "Bad named entity: pcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pcy;", 
+            "description": "Named entity: pcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u043f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&percnt", 
+            "description": "Bad named entity: percnt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&percnt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&percnt;", 
+            "description": "Named entity: percnt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "%"
+                ]
+            ]
+        }, 
+        {
+            "input": "&period", 
+            "description": "Bad named entity: period without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&period"
+                ]
+            ]
+        }, 
+        {
+            "input": "&period;", 
+            "description": "Named entity: period; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "."
+                ]
+            ]
+        }, 
+        {
+            "input": "&permil", 
+            "description": "Bad named entity: permil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&permil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&permil;", 
+            "description": "Named entity: permil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2030"
+                ]
+            ]
+        }, 
+        {
+            "input": "&perp", 
+            "description": "Bad named entity: perp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&perp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&perp;", 
+            "description": "Named entity: perp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pertenk", 
+            "description": "Bad named entity: pertenk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pertenk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pertenk;", 
+            "description": "Named entity: pertenk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2031"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pfr", 
+            "description": "Bad named entity: pfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pfr;", 
+            "description": "Named entity: pfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd2d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phi", 
+            "description": "Bad named entity: phi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&phi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phi;", 
+            "description": "Named entity: phi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phiv", 
+            "description": "Bad named entity: phiv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&phiv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phiv;", 
+            "description": "Named entity: phiv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phmmat", 
+            "description": "Bad named entity: phmmat without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&phmmat"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phmmat;", 
+            "description": "Named entity: phmmat; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2133"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phone", 
+            "description": "Bad named entity: phone without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&phone"
+                ]
+            ]
+        }, 
+        {
+            "input": "&phone;", 
+            "description": "Named entity: phone; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u260e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pi", 
+            "description": "Bad named entity: pi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pi;", 
+            "description": "Named entity: pi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pitchfork", 
+            "description": "Bad named entity: pitchfork without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pitchfork"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pitchfork;", 
+            "description": "Named entity: pitchfork; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22d4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&piv", 
+            "description": "Bad named entity: piv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&piv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&piv;", 
+            "description": "Named entity: piv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&planck", 
+            "description": "Bad named entity: planck without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&planck"
+                ]
+            ]
+        }, 
+        {
+            "input": "&planck;", 
+            "description": "Named entity: planck; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&planckh", 
+            "description": "Bad named entity: planckh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&planckh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&planckh;", 
+            "description": "Named entity: planckh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plankv", 
+            "description": "Bad named entity: plankv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plankv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plankv;", 
+            "description": "Named entity: plankv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plus", 
+            "description": "Bad named entity: plus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plus;", 
+            "description": "Named entity: plus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "+"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusacir", 
+            "description": "Bad named entity: plusacir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plusacir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusacir;", 
+            "description": "Named entity: plusacir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a23"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusb", 
+            "description": "Bad named entity: plusb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plusb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusb;", 
+            "description": "Named entity: plusb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u229e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pluscir", 
+            "description": "Bad named entity: pluscir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pluscir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pluscir;", 
+            "description": "Named entity: pluscir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a22"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusdo", 
+            "description": "Bad named entity: plusdo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plusdo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusdo;", 
+            "description": "Named entity: plusdo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2214"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusdu", 
+            "description": "Bad named entity: plusdu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plusdu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusdu;", 
+            "description": "Named entity: plusdu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a25"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pluse", 
+            "description": "Bad named entity: pluse without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pluse"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pluse;", 
+            "description": "Named entity: pluse; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a72"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusmn", 
+            "description": "Named entity: plusmn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plusmn;", 
+            "description": "Named entity: plusmn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plussim", 
+            "description": "Bad named entity: plussim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plussim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plussim;", 
+            "description": "Named entity: plussim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a26"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plustwo", 
+            "description": "Bad named entity: plustwo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&plustwo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&plustwo;", 
+            "description": "Named entity: plustwo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a27"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pm", 
+            "description": "Bad named entity: pm without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pm"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pm;", 
+            "description": "Named entity: pm; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pointint", 
+            "description": "Bad named entity: pointint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pointint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pointint;", 
+            "description": "Named entity: pointint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a15"
+                ]
+            ]
+        }, 
+        {
+            "input": "&popf", 
+            "description": "Bad named entity: popf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&popf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&popf;", 
+            "description": "Named entity: popf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd61"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pound", 
+            "description": "Named entity: pound without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pound;", 
+            "description": "Named entity: pound; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pr", 
+            "description": "Bad named entity: pr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pr;", 
+            "description": "Named entity: pr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prE", 
+            "description": "Bad named entity: prE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prE;", 
+            "description": "Named entity: prE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prap", 
+            "description": "Bad named entity: prap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prap;", 
+            "description": "Named entity: prap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prcue", 
+            "description": "Bad named entity: prcue without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prcue"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prcue;", 
+            "description": "Named entity: prcue; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pre", 
+            "description": "Bad named entity: pre without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pre"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pre;", 
+            "description": "Named entity: pre; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aaf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prec", 
+            "description": "Bad named entity: prec without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prec;", 
+            "description": "Named entity: prec; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precapprox", 
+            "description": "Bad named entity: precapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&precapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precapprox;", 
+            "description": "Named entity: precapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&preccurlyeq", 
+            "description": "Bad named entity: preccurlyeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&preccurlyeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&preccurlyeq;", 
+            "description": "Named entity: preccurlyeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&preceq", 
+            "description": "Bad named entity: preceq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&preceq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&preceq;", 
+            "description": "Named entity: preceq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aaf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precnapprox", 
+            "description": "Bad named entity: precnapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&precnapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precnapprox;", 
+            "description": "Named entity: precnapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precneqq", 
+            "description": "Bad named entity: precneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&precneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precneqq;", 
+            "description": "Named entity: precneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precnsim", 
+            "description": "Bad named entity: precnsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&precnsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precnsim;", 
+            "description": "Named entity: precnsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precsim", 
+            "description": "Bad named entity: precsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&precsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&precsim;", 
+            "description": "Named entity: precsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prime", 
+            "description": "Bad named entity: prime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prime;", 
+            "description": "Named entity: prime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2032"
+                ]
+            ]
+        }, 
+        {
+            "input": "&primes", 
+            "description": "Bad named entity: primes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&primes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&primes;", 
+            "description": "Named entity: primes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2119"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prnE", 
+            "description": "Bad named entity: prnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prnE;", 
+            "description": "Named entity: prnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prnap", 
+            "description": "Bad named entity: prnap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prnap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prnap;", 
+            "description": "Named entity: prnap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prnsim", 
+            "description": "Bad named entity: prnsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prnsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prnsim;", 
+            "description": "Named entity: prnsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prod", 
+            "description": "Bad named entity: prod without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prod"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prod;", 
+            "description": "Named entity: prod; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u220f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&profalar", 
+            "description": "Bad named entity: profalar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&profalar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&profalar;", 
+            "description": "Named entity: profalar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u232e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&profline", 
+            "description": "Bad named entity: profline without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&profline"
+                ]
+            ]
+        }, 
+        {
+            "input": "&profline;", 
+            "description": "Named entity: profline; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2312"
+                ]
+            ]
+        }, 
+        {
+            "input": "&profsurf", 
+            "description": "Bad named entity: profsurf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&profsurf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&profsurf;", 
+            "description": "Named entity: profsurf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2313"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prop", 
+            "description": "Bad named entity: prop without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prop"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prop;", 
+            "description": "Named entity: prop; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&propto", 
+            "description": "Bad named entity: propto without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&propto"
+                ]
+            ]
+        }, 
+        {
+            "input": "&propto;", 
+            "description": "Named entity: propto; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prsim", 
+            "description": "Bad named entity: prsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prsim;", 
+            "description": "Named entity: prsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prurel", 
+            "description": "Bad named entity: prurel without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&prurel"
+                ]
+            ]
+        }, 
+        {
+            "input": "&prurel;", 
+            "description": "Named entity: prurel; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pscr", 
+            "description": "Bad named entity: pscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&pscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&pscr;", 
+            "description": "Named entity: pscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&psi", 
+            "description": "Bad named entity: psi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&psi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&psi;", 
+            "description": "Named entity: psi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&puncsp", 
+            "description": "Bad named entity: puncsp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&puncsp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&puncsp;", 
+            "description": "Named entity: puncsp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2008"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qfr", 
+            "description": "Bad named entity: qfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&qfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qfr;", 
+            "description": "Named entity: qfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd2e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qint", 
+            "description": "Bad named entity: qint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&qint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qint;", 
+            "description": "Named entity: qint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a0c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qopf", 
+            "description": "Bad named entity: qopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&qopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qopf;", 
+            "description": "Named entity: qopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd62"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qprime", 
+            "description": "Bad named entity: qprime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&qprime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qprime;", 
+            "description": "Named entity: qprime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2057"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qscr", 
+            "description": "Bad named entity: qscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&qscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&qscr;", 
+            "description": "Named entity: qscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&quaternions", 
+            "description": "Bad named entity: quaternions without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&quaternions"
+                ]
+            ]
+        }, 
+        {
+            "input": "&quaternions;", 
+            "description": "Named entity: quaternions; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u210d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&quatint", 
+            "description": "Bad named entity: quatint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&quatint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&quatint;", 
+            "description": "Named entity: quatint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a16"
+                ]
+            ]
+        }, 
+        {
+            "input": "&quest", 
+            "description": "Bad named entity: quest without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&quest"
+                ]
+            ]
+        }, 
+        {
+            "input": "&quest;", 
+            "description": "Named entity: quest; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "?"
+                ]
+            ]
+        }, 
+        {
+            "input": "&questeq", 
+            "description": "Bad named entity: questeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&questeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&questeq;", 
+            "description": "Named entity: questeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u225f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&quot", 
+            "description": "Named entity: quot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\""
+                ]
+            ]
+        }, 
+        {
+            "input": "&quot;", 
+            "description": "Named entity: quot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\""
+                ]
+            ]
+        }, 
+        {
+            "input": "&rAarr", 
+            "description": "Bad named entity: rAarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rAarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rAarr;", 
+            "description": "Named entity: rAarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rArr", 
+            "description": "Bad named entity: rArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rArr;", 
+            "description": "Named entity: rArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rAtail", 
+            "description": "Bad named entity: rAtail without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rAtail"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rAtail;", 
+            "description": "Named entity: rAtail; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u291c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rBarr", 
+            "description": "Bad named entity: rBarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rBarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rBarr;", 
+            "description": "Named entity: rBarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u290f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rHar", 
+            "description": "Bad named entity: rHar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rHar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rHar;", 
+            "description": "Named entity: rHar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2964"
+                ]
+            ]
+        }, 
+        {
+            "input": "&race", 
+            "description": "Bad named entity: race without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&race"
+                ]
+            ]
+        }, 
+        {
+            "input": "&race;", 
+            "description": "Named entity: race; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223d\u0331"
+                ]
+            ]
+        }, 
+        {
+            "input": "&racute", 
+            "description": "Bad named entity: racute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&racute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&racute;", 
+            "description": "Named entity: racute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0155"
+                ]
+            ]
+        }, 
+        {
+            "input": "&radic", 
+            "description": "Bad named entity: radic without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&radic"
+                ]
+            ]
+        }, 
+        {
+            "input": "&radic;", 
+            "description": "Named entity: radic; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&raemptyv", 
+            "description": "Bad named entity: raemptyv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&raemptyv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&raemptyv;", 
+            "description": "Named entity: raemptyv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rang", 
+            "description": "Bad named entity: rang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rang;", 
+            "description": "Named entity: rang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rangd", 
+            "description": "Bad named entity: rangd without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rangd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rangd;", 
+            "description": "Named entity: rangd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2992"
+                ]
+            ]
+        }, 
+        {
+            "input": "&range", 
+            "description": "Bad named entity: range without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&range"
+                ]
+            ]
+        }, 
+        {
+            "input": "&range;", 
+            "description": "Named entity: range; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rangle", 
+            "description": "Bad named entity: rangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rangle;", 
+            "description": "Named entity: rangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&raquo", 
+            "description": "Named entity: raquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00bb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&raquo;", 
+            "description": "Named entity: raquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00bb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarr", 
+            "description": "Bad named entity: rarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarr;", 
+            "description": "Named entity: rarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2192"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrap", 
+            "description": "Bad named entity: rarrap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrap;", 
+            "description": "Named entity: rarrap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2975"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrb", 
+            "description": "Bad named entity: rarrb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrb;", 
+            "description": "Named entity: rarrb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21e5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrbfs", 
+            "description": "Bad named entity: rarrbfs without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrbfs"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrbfs;", 
+            "description": "Named entity: rarrbfs; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2920"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrc", 
+            "description": "Bad named entity: rarrc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrc;", 
+            "description": "Named entity: rarrc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2933"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrfs", 
+            "description": "Bad named entity: rarrfs without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrfs"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrfs;", 
+            "description": "Named entity: rarrfs; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u291e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrhk", 
+            "description": "Bad named entity: rarrhk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrhk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrhk;", 
+            "description": "Named entity: rarrhk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrlp", 
+            "description": "Bad named entity: rarrlp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrlp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrlp;", 
+            "description": "Named entity: rarrlp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21ac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrpl", 
+            "description": "Bad named entity: rarrpl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrpl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrpl;", 
+            "description": "Named entity: rarrpl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2945"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrsim", 
+            "description": "Bad named entity: rarrsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrsim;", 
+            "description": "Named entity: rarrsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2974"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrtl", 
+            "description": "Bad named entity: rarrtl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrtl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrtl;", 
+            "description": "Named entity: rarrtl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrw", 
+            "description": "Bad named entity: rarrw without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rarrw"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rarrw;", 
+            "description": "Named entity: rarrw; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ratail", 
+            "description": "Bad named entity: ratail without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ratail"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ratail;", 
+            "description": "Named entity: ratail; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u291a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ratio", 
+            "description": "Bad named entity: ratio without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ratio"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ratio;", 
+            "description": "Named entity: ratio; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2236"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rationals", 
+            "description": "Bad named entity: rationals without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rationals"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rationals;", 
+            "description": "Named entity: rationals; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbarr", 
+            "description": "Bad named entity: rbarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rbarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbarr;", 
+            "description": "Named entity: rbarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u290d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbbrk", 
+            "description": "Bad named entity: rbbrk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rbbrk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbbrk;", 
+            "description": "Named entity: rbbrk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2773"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrace", 
+            "description": "Bad named entity: rbrace without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rbrace"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrace;", 
+            "description": "Named entity: rbrace; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "}"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrack", 
+            "description": "Bad named entity: rbrack without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rbrack"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrack;", 
+            "description": "Named entity: rbrack; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "]"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrke", 
+            "description": "Bad named entity: rbrke without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rbrke"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrke;", 
+            "description": "Named entity: rbrke; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u298c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrksld", 
+            "description": "Bad named entity: rbrksld without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rbrksld"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrksld;", 
+            "description": "Named entity: rbrksld; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u298e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrkslu", 
+            "description": "Bad named entity: rbrkslu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rbrkslu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rbrkslu;", 
+            "description": "Named entity: rbrkslu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2990"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcaron", 
+            "description": "Bad named entity: rcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcaron;", 
+            "description": "Named entity: rcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0159"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcedil", 
+            "description": "Bad named entity: rcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcedil;", 
+            "description": "Named entity: rcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0157"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rceil", 
+            "description": "Bad named entity: rceil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rceil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rceil;", 
+            "description": "Named entity: rceil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2309"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcub", 
+            "description": "Bad named entity: rcub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rcub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcub;", 
+            "description": "Named entity: rcub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "}"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcy", 
+            "description": "Bad named entity: rcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rcy;", 
+            "description": "Named entity: rcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0440"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdca", 
+            "description": "Bad named entity: rdca without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rdca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdca;", 
+            "description": "Named entity: rdca; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2937"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdldhar", 
+            "description": "Bad named entity: rdldhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rdldhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdldhar;", 
+            "description": "Named entity: rdldhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2969"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdquo", 
+            "description": "Bad named entity: rdquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rdquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdquo;", 
+            "description": "Named entity: rdquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdquor", 
+            "description": "Bad named entity: rdquor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rdquor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdquor;", 
+            "description": "Named entity: rdquor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdsh", 
+            "description": "Bad named entity: rdsh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rdsh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rdsh;", 
+            "description": "Named entity: rdsh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&real", 
+            "description": "Bad named entity: real without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&real"
+                ]
+            ]
+        }, 
+        {
+            "input": "&real;", 
+            "description": "Named entity: real; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&realine", 
+            "description": "Bad named entity: realine without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&realine"
+                ]
+            ]
+        }, 
+        {
+            "input": "&realine;", 
+            "description": "Named entity: realine; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&realpart", 
+            "description": "Bad named entity: realpart without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&realpart"
+                ]
+            ]
+        }, 
+        {
+            "input": "&realpart;", 
+            "description": "Named entity: realpart; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&reals", 
+            "description": "Bad named entity: reals without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&reals"
+                ]
+            ]
+        }, 
+        {
+            "input": "&reals;", 
+            "description": "Named entity: reals; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rect", 
+            "description": "Bad named entity: rect without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rect"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rect;", 
+            "description": "Named entity: rect; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&reg", 
+            "description": "Named entity: reg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&reg;", 
+            "description": "Named entity: reg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ae"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rfisht", 
+            "description": "Bad named entity: rfisht without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rfisht"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rfisht;", 
+            "description": "Named entity: rfisht; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u297d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rfloor", 
+            "description": "Bad named entity: rfloor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rfloor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rfloor;", 
+            "description": "Named entity: rfloor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rfr", 
+            "description": "Bad named entity: rfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rfr;", 
+            "description": "Named entity: rfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd2f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rhard", 
+            "description": "Bad named entity: rhard without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rhard"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rhard;", 
+            "description": "Named entity: rhard; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rharu", 
+            "description": "Bad named entity: rharu without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rharu"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rharu;", 
+            "description": "Named entity: rharu; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rharul", 
+            "description": "Bad named entity: rharul without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rharul"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rharul;", 
+            "description": "Named entity: rharul; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rho", 
+            "description": "Bad named entity: rho without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rho"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rho;", 
+            "description": "Named entity: rho; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rhov", 
+            "description": "Bad named entity: rhov without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rhov"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rhov;", 
+            "description": "Named entity: rhov; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightarrow", 
+            "description": "Bad named entity: rightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightarrow;", 
+            "description": "Named entity: rightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2192"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightarrowtail", 
+            "description": "Bad named entity: rightarrowtail without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightarrowtail"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightarrowtail;", 
+            "description": "Named entity: rightarrowtail; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightharpoondown", 
+            "description": "Bad named entity: rightharpoondown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightharpoondown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightharpoondown;", 
+            "description": "Named entity: rightharpoondown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightharpoonup", 
+            "description": "Bad named entity: rightharpoonup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightharpoonup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightharpoonup;", 
+            "description": "Named entity: rightharpoonup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightleftarrows", 
+            "description": "Bad named entity: rightleftarrows without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightleftarrows"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightleftarrows;", 
+            "description": "Named entity: rightleftarrows; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightleftharpoons", 
+            "description": "Bad named entity: rightleftharpoons without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightleftharpoons"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightleftharpoons;", 
+            "description": "Named entity: rightleftharpoons; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightrightarrows", 
+            "description": "Bad named entity: rightrightarrows without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightrightarrows"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightrightarrows;", 
+            "description": "Named entity: rightrightarrows; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightsquigarrow", 
+            "description": "Bad named entity: rightsquigarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightsquigarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightsquigarrow;", 
+            "description": "Named entity: rightsquigarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightthreetimes", 
+            "description": "Bad named entity: rightthreetimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rightthreetimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rightthreetimes;", 
+            "description": "Named entity: rightthreetimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ring", 
+            "description": "Bad named entity: ring without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ring"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ring;", 
+            "description": "Named entity: ring; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02da"
+                ]
+            ]
+        }, 
+        {
+            "input": "&risingdotseq", 
+            "description": "Bad named entity: risingdotseq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&risingdotseq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&risingdotseq;", 
+            "description": "Named entity: risingdotseq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2253"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rlarr", 
+            "description": "Bad named entity: rlarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rlarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rlarr;", 
+            "description": "Named entity: rlarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rlhar", 
+            "description": "Bad named entity: rlhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rlhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rlhar;", 
+            "description": "Named entity: rlhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21cc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rlm", 
+            "description": "Bad named entity: rlm without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rlm"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rlm;", 
+            "description": "Named entity: rlm; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rmoust", 
+            "description": "Bad named entity: rmoust without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rmoust"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rmoust;", 
+            "description": "Named entity: rmoust; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rmoustache", 
+            "description": "Bad named entity: rmoustache without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rmoustache"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rmoustache;", 
+            "description": "Named entity: rmoustache; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rnmid", 
+            "description": "Bad named entity: rnmid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rnmid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rnmid;", 
+            "description": "Named entity: rnmid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&roang", 
+            "description": "Bad named entity: roang without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&roang"
+                ]
+            ]
+        }, 
+        {
+            "input": "&roang;", 
+            "description": "Named entity: roang; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27ed"
+                ]
+            ]
+        }, 
+        {
+            "input": "&roarr", 
+            "description": "Bad named entity: roarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&roarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&roarr;", 
+            "description": "Named entity: roarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21fe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&robrk", 
+            "description": "Bad named entity: robrk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&robrk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&robrk;", 
+            "description": "Named entity: robrk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27e7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ropar", 
+            "description": "Bad named entity: ropar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ropar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ropar;", 
+            "description": "Named entity: ropar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2986"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ropf", 
+            "description": "Bad named entity: ropf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ropf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ropf;", 
+            "description": "Named entity: ropf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd63"
+                ]
+            ]
+        }, 
+        {
+            "input": "&roplus", 
+            "description": "Bad named entity: roplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&roplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&roplus;", 
+            "description": "Named entity: roplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a2e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rotimes", 
+            "description": "Bad named entity: rotimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rotimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rotimes;", 
+            "description": "Named entity: rotimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a35"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rpar", 
+            "description": "Bad named entity: rpar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rpar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rpar;", 
+            "description": "Named entity: rpar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    ")"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rpargt", 
+            "description": "Bad named entity: rpargt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rpargt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rpargt;", 
+            "description": "Named entity: rpargt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2994"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rppolint", 
+            "description": "Bad named entity: rppolint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rppolint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rppolint;", 
+            "description": "Named entity: rppolint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a12"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rrarr", 
+            "description": "Bad named entity: rrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rrarr;", 
+            "description": "Named entity: rrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsaquo", 
+            "description": "Bad named entity: rsaquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rsaquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsaquo;", 
+            "description": "Named entity: rsaquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u203a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rscr", 
+            "description": "Bad named entity: rscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rscr;", 
+            "description": "Named entity: rscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsh", 
+            "description": "Bad named entity: rsh without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rsh"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsh;", 
+            "description": "Named entity: rsh; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21b1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsqb", 
+            "description": "Bad named entity: rsqb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rsqb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsqb;", 
+            "description": "Named entity: rsqb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "]"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsquo", 
+            "description": "Bad named entity: rsquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rsquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsquo;", 
+            "description": "Named entity: rsquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2019"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsquor", 
+            "description": "Bad named entity: rsquor without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rsquor"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rsquor;", 
+            "description": "Named entity: rsquor; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2019"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rthree", 
+            "description": "Bad named entity: rthree without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rthree"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rthree;", 
+            "description": "Named entity: rthree; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22cc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtimes", 
+            "description": "Bad named entity: rtimes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rtimes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtimes;", 
+            "description": "Named entity: rtimes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtri", 
+            "description": "Bad named entity: rtri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rtri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtri;", 
+            "description": "Named entity: rtri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtrie", 
+            "description": "Bad named entity: rtrie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rtrie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtrie;", 
+            "description": "Named entity: rtrie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtrif", 
+            "description": "Bad named entity: rtrif without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rtrif"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtrif;", 
+            "description": "Named entity: rtrif; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtriltri", 
+            "description": "Bad named entity: rtriltri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rtriltri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rtriltri;", 
+            "description": "Named entity: rtriltri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29ce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ruluhar", 
+            "description": "Bad named entity: ruluhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ruluhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ruluhar;", 
+            "description": "Named entity: ruluhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2968"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rx", 
+            "description": "Bad named entity: rx without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&rx"
+                ]
+            ]
+        }, 
+        {
+            "input": "&rx;", 
+            "description": "Named entity: rx; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u211e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sacute", 
+            "description": "Bad named entity: sacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sacute;", 
+            "description": "Named entity: sacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u015b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sbquo", 
+            "description": "Bad named entity: sbquo without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sbquo"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sbquo;", 
+            "description": "Named entity: sbquo; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u201a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sc", 
+            "description": "Bad named entity: sc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sc;", 
+            "description": "Named entity: sc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scE", 
+            "description": "Bad named entity: scE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scE;", 
+            "description": "Named entity: scE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scap", 
+            "description": "Bad named entity: scap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scap;", 
+            "description": "Named entity: scap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scaron", 
+            "description": "Bad named entity: scaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scaron;", 
+            "description": "Named entity: scaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0161"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sccue", 
+            "description": "Bad named entity: sccue without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sccue"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sccue;", 
+            "description": "Named entity: sccue; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sce", 
+            "description": "Bad named entity: sce without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sce;", 
+            "description": "Named entity: sce; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scedil", 
+            "description": "Bad named entity: scedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scedil;", 
+            "description": "Named entity: scedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u015f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scirc", 
+            "description": "Bad named entity: scirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scirc;", 
+            "description": "Named entity: scirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u015d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scnE", 
+            "description": "Bad named entity: scnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scnE;", 
+            "description": "Named entity: scnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scnap", 
+            "description": "Bad named entity: scnap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scnap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scnap;", 
+            "description": "Named entity: scnap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scnsim", 
+            "description": "Bad named entity: scnsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scnsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scnsim;", 
+            "description": "Named entity: scnsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scpolint", 
+            "description": "Bad named entity: scpolint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scpolint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scpolint;", 
+            "description": "Named entity: scpolint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a13"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scsim", 
+            "description": "Bad named entity: scsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scsim;", 
+            "description": "Named entity: scsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scy", 
+            "description": "Bad named entity: scy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&scy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&scy;", 
+            "description": "Named entity: scy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0441"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sdot", 
+            "description": "Bad named entity: sdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sdot;", 
+            "description": "Named entity: sdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sdotb", 
+            "description": "Bad named entity: sdotb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sdotb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sdotb;", 
+            "description": "Named entity: sdotb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sdote", 
+            "description": "Bad named entity: sdote without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sdote"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sdote;", 
+            "description": "Named entity: sdote; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a66"
+                ]
+            ]
+        }, 
+        {
+            "input": "&seArr", 
+            "description": "Bad named entity: seArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&seArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&seArr;", 
+            "description": "Named entity: seArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&searhk", 
+            "description": "Bad named entity: searhk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&searhk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&searhk;", 
+            "description": "Named entity: searhk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2925"
+                ]
+            ]
+        }, 
+        {
+            "input": "&searr", 
+            "description": "Bad named entity: searr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&searr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&searr;", 
+            "description": "Named entity: searr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2198"
+                ]
+            ]
+        }, 
+        {
+            "input": "&searrow", 
+            "description": "Bad named entity: searrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&searrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&searrow;", 
+            "description": "Named entity: searrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2198"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sect", 
+            "description": "Named entity: sect without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sect;", 
+            "description": "Named entity: sect; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&semi", 
+            "description": "Bad named entity: semi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&semi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&semi;", 
+            "description": "Named entity: semi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    ";"
+                ]
+            ]
+        }, 
+        {
+            "input": "&seswar", 
+            "description": "Bad named entity: seswar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&seswar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&seswar;", 
+            "description": "Named entity: seswar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2929"
+                ]
+            ]
+        }, 
+        {
+            "input": "&setminus", 
+            "description": "Bad named entity: setminus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&setminus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&setminus;", 
+            "description": "Named entity: setminus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2216"
+                ]
+            ]
+        }, 
+        {
+            "input": "&setmn", 
+            "description": "Bad named entity: setmn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&setmn"
+                ]
+            ]
+        }, 
+        {
+            "input": "&setmn;", 
+            "description": "Named entity: setmn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2216"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sext", 
+            "description": "Bad named entity: sext without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sext"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sext;", 
+            "description": "Named entity: sext; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2736"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sfr", 
+            "description": "Bad named entity: sfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sfr;", 
+            "description": "Named entity: sfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd30"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sfrown", 
+            "description": "Bad named entity: sfrown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sfrown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sfrown;", 
+            "description": "Named entity: sfrown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2322"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sharp", 
+            "description": "Bad named entity: sharp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sharp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sharp;", 
+            "description": "Named entity: sharp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u266f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shchcy", 
+            "description": "Bad named entity: shchcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&shchcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shchcy;", 
+            "description": "Named entity: shchcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0449"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shcy", 
+            "description": "Bad named entity: shcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&shcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shcy;", 
+            "description": "Named entity: shcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0448"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shortmid", 
+            "description": "Bad named entity: shortmid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&shortmid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shortmid;", 
+            "description": "Named entity: shortmid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2223"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shortparallel", 
+            "description": "Bad named entity: shortparallel without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&shortparallel"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shortparallel;", 
+            "description": "Named entity: shortparallel; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2225"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shy", 
+            "description": "Named entity: shy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&shy;", 
+            "description": "Named entity: shy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ad"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sigma", 
+            "description": "Bad named entity: sigma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sigma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sigma;", 
+            "description": "Named entity: sigma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sigmaf", 
+            "description": "Bad named entity: sigmaf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sigmaf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sigmaf;", 
+            "description": "Named entity: sigmaf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sigmav", 
+            "description": "Bad named entity: sigmav without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sigmav"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sigmav;", 
+            "description": "Named entity: sigmav; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sim", 
+            "description": "Bad named entity: sim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sim;", 
+            "description": "Named entity: sim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simdot", 
+            "description": "Bad named entity: simdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simdot;", 
+            "description": "Named entity: simdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a6a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sime", 
+            "description": "Bad named entity: sime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sime;", 
+            "description": "Named entity: sime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2243"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simeq", 
+            "description": "Bad named entity: simeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simeq;", 
+            "description": "Named entity: simeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2243"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simg", 
+            "description": "Bad named entity: simg without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simg"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simg;", 
+            "description": "Named entity: simg; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a9e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simgE", 
+            "description": "Bad named entity: simgE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simgE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simgE;", 
+            "description": "Named entity: simgE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aa0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&siml", 
+            "description": "Bad named entity: siml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&siml"
+                ]
+            ]
+        }, 
+        {
+            "input": "&siml;", 
+            "description": "Named entity: siml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a9d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simlE", 
+            "description": "Bad named entity: simlE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simlE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simlE;", 
+            "description": "Named entity: simlE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a9f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simne", 
+            "description": "Bad named entity: simne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simne;", 
+            "description": "Named entity: simne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2246"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simplus", 
+            "description": "Bad named entity: simplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simplus;", 
+            "description": "Named entity: simplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a24"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simrarr", 
+            "description": "Bad named entity: simrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&simrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&simrarr;", 
+            "description": "Named entity: simrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2972"
+                ]
+            ]
+        }, 
+        {
+            "input": "&slarr", 
+            "description": "Bad named entity: slarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&slarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&slarr;", 
+            "description": "Named entity: slarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2190"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smallsetminus", 
+            "description": "Bad named entity: smallsetminus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smallsetminus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smallsetminus;", 
+            "description": "Named entity: smallsetminus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2216"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smashp", 
+            "description": "Bad named entity: smashp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smashp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smashp;", 
+            "description": "Named entity: smashp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a33"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smeparsl", 
+            "description": "Bad named entity: smeparsl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smeparsl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smeparsl;", 
+            "description": "Named entity: smeparsl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29e4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smid", 
+            "description": "Bad named entity: smid without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smid"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smid;", 
+            "description": "Named entity: smid; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2223"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smile", 
+            "description": "Bad named entity: smile without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smile"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smile;", 
+            "description": "Named entity: smile; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2323"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smt", 
+            "description": "Bad named entity: smt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smt;", 
+            "description": "Named entity: smt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aaa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smte", 
+            "description": "Bad named entity: smte without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smte"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smte;", 
+            "description": "Named entity: smte; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smtes", 
+            "description": "Bad named entity: smtes without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&smtes"
+                ]
+            ]
+        }, 
+        {
+            "input": "&smtes;", 
+            "description": "Named entity: smtes; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aac\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&softcy", 
+            "description": "Bad named entity: softcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&softcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&softcy;", 
+            "description": "Named entity: softcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u044c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sol", 
+            "description": "Bad named entity: sol without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sol"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sol;", 
+            "description": "Named entity: sol; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "/"
+                ]
+            ]
+        }, 
+        {
+            "input": "&solb", 
+            "description": "Bad named entity: solb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&solb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&solb;", 
+            "description": "Named entity: solb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&solbar", 
+            "description": "Bad named entity: solbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&solbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&solbar;", 
+            "description": "Named entity: solbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u233f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sopf", 
+            "description": "Bad named entity: sopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sopf;", 
+            "description": "Named entity: sopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd64"
+                ]
+            ]
+        }, 
+        {
+            "input": "&spades", 
+            "description": "Bad named entity: spades without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&spades"
+                ]
+            ]
+        }, 
+        {
+            "input": "&spades;", 
+            "description": "Named entity: spades; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2660"
+                ]
+            ]
+        }, 
+        {
+            "input": "&spadesuit", 
+            "description": "Bad named entity: spadesuit without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&spadesuit"
+                ]
+            ]
+        }, 
+        {
+            "input": "&spadesuit;", 
+            "description": "Named entity: spadesuit; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2660"
+                ]
+            ]
+        }, 
+        {
+            "input": "&spar", 
+            "description": "Bad named entity: spar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&spar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&spar;", 
+            "description": "Named entity: spar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2225"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcap", 
+            "description": "Bad named entity: sqcap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqcap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcap;", 
+            "description": "Named entity: sqcap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2293"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcaps", 
+            "description": "Bad named entity: sqcaps without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqcaps"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcaps;", 
+            "description": "Named entity: sqcaps; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2293\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcup", 
+            "description": "Bad named entity: sqcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcup;", 
+            "description": "Named entity: sqcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2294"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcups", 
+            "description": "Bad named entity: sqcups without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqcups"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqcups;", 
+            "description": "Named entity: sqcups; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2294\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsub", 
+            "description": "Bad named entity: sqsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsub;", 
+            "description": "Named entity: sqsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsube", 
+            "description": "Bad named entity: sqsube without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsube"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsube;", 
+            "description": "Named entity: sqsube; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2291"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsubset", 
+            "description": "Bad named entity: sqsubset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsubset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsubset;", 
+            "description": "Named entity: sqsubset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsubseteq", 
+            "description": "Bad named entity: sqsubseteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsubseteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsubseteq;", 
+            "description": "Named entity: sqsubseteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2291"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsup", 
+            "description": "Bad named entity: sqsup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsup;", 
+            "description": "Named entity: sqsup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2290"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsupe", 
+            "description": "Bad named entity: sqsupe without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsupe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsupe;", 
+            "description": "Named entity: sqsupe; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2292"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsupset", 
+            "description": "Bad named entity: sqsupset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsupset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsupset;", 
+            "description": "Named entity: sqsupset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2290"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsupseteq", 
+            "description": "Bad named entity: sqsupseteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sqsupseteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sqsupseteq;", 
+            "description": "Named entity: sqsupseteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2292"
+                ]
+            ]
+        }, 
+        {
+            "input": "&squ", 
+            "description": "Bad named entity: squ without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&squ"
+                ]
+            ]
+        }, 
+        {
+            "input": "&squ;", 
+            "description": "Named entity: squ; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&square", 
+            "description": "Bad named entity: square without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&square"
+                ]
+            ]
+        }, 
+        {
+            "input": "&square;", 
+            "description": "Named entity: square; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25a1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&squarf", 
+            "description": "Bad named entity: squarf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&squarf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&squarf;", 
+            "description": "Named entity: squarf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&squf", 
+            "description": "Bad named entity: squf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&squf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&squf;", 
+            "description": "Named entity: squf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25aa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&srarr", 
+            "description": "Bad named entity: srarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&srarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&srarr;", 
+            "description": "Named entity: srarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2192"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sscr", 
+            "description": "Bad named entity: sscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sscr;", 
+            "description": "Named entity: sscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ssetmn", 
+            "description": "Bad named entity: ssetmn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ssetmn"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ssetmn;", 
+            "description": "Named entity: ssetmn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2216"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ssmile", 
+            "description": "Bad named entity: ssmile without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ssmile"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ssmile;", 
+            "description": "Named entity: ssmile; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2323"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sstarf", 
+            "description": "Bad named entity: sstarf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sstarf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sstarf;", 
+            "description": "Named entity: sstarf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&star", 
+            "description": "Bad named entity: star without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&star"
+                ]
+            ]
+        }, 
+        {
+            "input": "&star;", 
+            "description": "Named entity: star; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2606"
+                ]
+            ]
+        }, 
+        {
+            "input": "&starf", 
+            "description": "Bad named entity: starf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&starf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&starf;", 
+            "description": "Named entity: starf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2605"
+                ]
+            ]
+        }, 
+        {
+            "input": "&straightepsilon", 
+            "description": "Bad named entity: straightepsilon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&straightepsilon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&straightepsilon;", 
+            "description": "Named entity: straightepsilon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&straightphi", 
+            "description": "Bad named entity: straightphi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&straightphi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&straightphi;", 
+            "description": "Named entity: straightphi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&strns", 
+            "description": "Bad named entity: strns without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&strns"
+                ]
+            ]
+        }, 
+        {
+            "input": "&strns;", 
+            "description": "Named entity: strns; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00af"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sub", 
+            "description": "Bad named entity: sub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sub;", 
+            "description": "Named entity: sub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2282"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subE", 
+            "description": "Bad named entity: subE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subE;", 
+            "description": "Named entity: subE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subdot", 
+            "description": "Bad named entity: subdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subdot;", 
+            "description": "Named entity: subdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2abd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sube", 
+            "description": "Bad named entity: sube without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sube"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sube;", 
+            "description": "Named entity: sube; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2286"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subedot", 
+            "description": "Bad named entity: subedot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subedot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subedot;", 
+            "description": "Named entity: subedot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&submult", 
+            "description": "Bad named entity: submult without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&submult"
+                ]
+            ]
+        }, 
+        {
+            "input": "&submult;", 
+            "description": "Named entity: submult; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subnE", 
+            "description": "Bad named entity: subnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subnE;", 
+            "description": "Named entity: subnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subne", 
+            "description": "Bad named entity: subne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subne;", 
+            "description": "Named entity: subne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subplus", 
+            "description": "Bad named entity: subplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subplus;", 
+            "description": "Named entity: subplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2abf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subrarr", 
+            "description": "Bad named entity: subrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subrarr;", 
+            "description": "Named entity: subrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2979"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subset", 
+            "description": "Bad named entity: subset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subset;", 
+            "description": "Named entity: subset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2282"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subseteq", 
+            "description": "Bad named entity: subseteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subseteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subseteq;", 
+            "description": "Named entity: subseteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2286"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subseteqq", 
+            "description": "Bad named entity: subseteqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subseteqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subseteqq;", 
+            "description": "Named entity: subseteqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsetneq", 
+            "description": "Bad named entity: subsetneq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subsetneq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsetneq;", 
+            "description": "Named entity: subsetneq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsetneqq", 
+            "description": "Bad named entity: subsetneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subsetneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsetneqq;", 
+            "description": "Named entity: subsetneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsim", 
+            "description": "Bad named entity: subsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsim;", 
+            "description": "Named entity: subsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsub", 
+            "description": "Bad named entity: subsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsub;", 
+            "description": "Named entity: subsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsup", 
+            "description": "Bad named entity: subsup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&subsup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&subsup;", 
+            "description": "Named entity: subsup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succ", 
+            "description": "Bad named entity: succ without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succ"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succ;", 
+            "description": "Named entity: succ; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succapprox", 
+            "description": "Bad named entity: succapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succapprox;", 
+            "description": "Named entity: succapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succcurlyeq", 
+            "description": "Bad named entity: succcurlyeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succcurlyeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succcurlyeq;", 
+            "description": "Named entity: succcurlyeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succeq", 
+            "description": "Bad named entity: succeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succeq;", 
+            "description": "Named entity: succeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succnapprox", 
+            "description": "Bad named entity: succnapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succnapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succnapprox;", 
+            "description": "Named entity: succnapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2aba"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succneqq", 
+            "description": "Bad named entity: succneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succneqq;", 
+            "description": "Named entity: succneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ab6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succnsim", 
+            "description": "Bad named entity: succnsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succnsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succnsim;", 
+            "description": "Named entity: succnsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22e9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succsim", 
+            "description": "Bad named entity: succsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&succsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&succsim;", 
+            "description": "Named entity: succsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u227f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sum", 
+            "description": "Bad named entity: sum without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sum"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sum;", 
+            "description": "Named entity: sum; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2211"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sung", 
+            "description": "Bad named entity: sung without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sung"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sung;", 
+            "description": "Named entity: sung; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u266a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup", 
+            "description": "Bad named entity: sup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&sup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup1", 
+            "description": "Named entity: sup1 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup1;", 
+            "description": "Named entity: sup1; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup2", 
+            "description": "Named entity: sup2 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup2;", 
+            "description": "Named entity: sup2; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup3", 
+            "description": "Named entity: sup3 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup3;", 
+            "description": "Named entity: sup3; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&sup;", 
+            "description": "Named entity: sup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2283"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supE", 
+            "description": "Bad named entity: supE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supE;", 
+            "description": "Named entity: supE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supdot", 
+            "description": "Bad named entity: supdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supdot;", 
+            "description": "Named entity: supdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2abe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supdsub", 
+            "description": "Bad named entity: supdsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supdsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supdsub;", 
+            "description": "Named entity: supdsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supe", 
+            "description": "Bad named entity: supe without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supe;", 
+            "description": "Named entity: supe; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2287"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supedot", 
+            "description": "Bad named entity: supedot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supedot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supedot;", 
+            "description": "Named entity: supedot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&suphsol", 
+            "description": "Bad named entity: suphsol without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&suphsol"
+                ]
+            ]
+        }, 
+        {
+            "input": "&suphsol;", 
+            "description": "Named entity: suphsol; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27c9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&suphsub", 
+            "description": "Bad named entity: suphsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&suphsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&suphsub;", 
+            "description": "Named entity: suphsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&suplarr", 
+            "description": "Bad named entity: suplarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&suplarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&suplarr;", 
+            "description": "Named entity: suplarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u297b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supmult", 
+            "description": "Bad named entity: supmult without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supmult"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supmult;", 
+            "description": "Named entity: supmult; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supnE", 
+            "description": "Bad named entity: supnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supnE;", 
+            "description": "Named entity: supnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supne", 
+            "description": "Bad named entity: supne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supne;", 
+            "description": "Named entity: supne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supplus", 
+            "description": "Bad named entity: supplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supplus;", 
+            "description": "Named entity: supplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supset", 
+            "description": "Bad named entity: supset without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supset"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supset;", 
+            "description": "Named entity: supset; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2283"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supseteq", 
+            "description": "Bad named entity: supseteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supseteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supseteq;", 
+            "description": "Named entity: supseteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2287"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supseteqq", 
+            "description": "Bad named entity: supseteqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supseteqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supseteqq;", 
+            "description": "Named entity: supseteqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsetneq", 
+            "description": "Bad named entity: supsetneq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supsetneq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsetneq;", 
+            "description": "Named entity: supsetneq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsetneqq", 
+            "description": "Bad named entity: supsetneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supsetneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsetneqq;", 
+            "description": "Named entity: supsetneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsim", 
+            "description": "Bad named entity: supsim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supsim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsim;", 
+            "description": "Named entity: supsim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ac8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsub", 
+            "description": "Bad named entity: supsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsub;", 
+            "description": "Named entity: supsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsup", 
+            "description": "Bad named entity: supsup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&supsup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&supsup;", 
+            "description": "Named entity: supsup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ad6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swArr", 
+            "description": "Bad named entity: swArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&swArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swArr;", 
+            "description": "Named entity: swArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swarhk", 
+            "description": "Bad named entity: swarhk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&swarhk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swarhk;", 
+            "description": "Named entity: swarhk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2926"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swarr", 
+            "description": "Bad named entity: swarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&swarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swarr;", 
+            "description": "Named entity: swarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2199"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swarrow", 
+            "description": "Bad named entity: swarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&swarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swarrow;", 
+            "description": "Named entity: swarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2199"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swnwar", 
+            "description": "Bad named entity: swnwar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&swnwar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&swnwar;", 
+            "description": "Named entity: swnwar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u292a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&szlig", 
+            "description": "Named entity: szlig without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00df"
+                ]
+            ]
+        }, 
+        {
+            "input": "&szlig;", 
+            "description": "Named entity: szlig; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00df"
+                ]
+            ]
+        }, 
+        {
+            "input": "&target", 
+            "description": "Bad named entity: target without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&target"
+                ]
+            ]
+        }, 
+        {
+            "input": "&target;", 
+            "description": "Named entity: target; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2316"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tau", 
+            "description": "Bad named entity: tau without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tau"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tau;", 
+            "description": "Named entity: tau; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tbrk", 
+            "description": "Bad named entity: tbrk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tbrk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tbrk;", 
+            "description": "Named entity: tbrk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tcaron", 
+            "description": "Bad named entity: tcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tcaron;", 
+            "description": "Named entity: tcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0165"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tcedil", 
+            "description": "Bad named entity: tcedil without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tcedil"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tcedil;", 
+            "description": "Named entity: tcedil; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0163"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tcy", 
+            "description": "Bad named entity: tcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tcy;", 
+            "description": "Named entity: tcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0442"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tdot", 
+            "description": "Bad named entity: tdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tdot;", 
+            "description": "Named entity: tdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u20db"
+                ]
+            ]
+        }, 
+        {
+            "input": "&telrec", 
+            "description": "Bad named entity: telrec without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&telrec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&telrec;", 
+            "description": "Named entity: telrec; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2315"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tfr", 
+            "description": "Bad named entity: tfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tfr;", 
+            "description": "Named entity: tfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd31"
+                ]
+            ]
+        }, 
+        {
+            "input": "&there4", 
+            "description": "Bad named entity: there4 without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&there4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&there4;", 
+            "description": "Named entity: there4; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2234"
+                ]
+            ]
+        }, 
+        {
+            "input": "&therefore", 
+            "description": "Bad named entity: therefore without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&therefore"
+                ]
+            ]
+        }, 
+        {
+            "input": "&therefore;", 
+            "description": "Named entity: therefore; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2234"
+                ]
+            ]
+        }, 
+        {
+            "input": "&theta", 
+            "description": "Bad named entity: theta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&theta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&theta;", 
+            "description": "Named entity: theta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thetasym", 
+            "description": "Bad named entity: thetasym without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&thetasym"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thetasym;", 
+            "description": "Named entity: thetasym; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thetav", 
+            "description": "Bad named entity: thetav without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&thetav"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thetav;", 
+            "description": "Named entity: thetav; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thickapprox", 
+            "description": "Bad named entity: thickapprox without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&thickapprox"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thickapprox;", 
+            "description": "Named entity: thickapprox; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2248"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thicksim", 
+            "description": "Bad named entity: thicksim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&thicksim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thicksim;", 
+            "description": "Named entity: thicksim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thinsp", 
+            "description": "Bad named entity: thinsp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&thinsp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thinsp;", 
+            "description": "Named entity: thinsp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2009"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thkap", 
+            "description": "Bad named entity: thkap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&thkap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thkap;", 
+            "description": "Named entity: thkap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2248"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thksim", 
+            "description": "Bad named entity: thksim without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&thksim"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thksim;", 
+            "description": "Named entity: thksim; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u223c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thorn", 
+            "description": "Named entity: thorn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00fe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&thorn;", 
+            "description": "Named entity: thorn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00fe"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tilde", 
+            "description": "Bad named entity: tilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tilde;", 
+            "description": "Named entity: tilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u02dc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&times", 
+            "description": "Named entity: times without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00d7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&times;", 
+            "description": "Named entity: times; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00d7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&timesb;", 
+            "description": "Named entity: timesb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&timesbar;", 
+            "description": "Named entity: timesbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a31"
+                ]
+            ]
+        }, 
+        {
+            "input": "&timesd;", 
+            "description": "Named entity: timesd; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a30"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tint", 
+            "description": "Bad named entity: tint without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tint"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tint;", 
+            "description": "Named entity: tint; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u222d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&toea", 
+            "description": "Bad named entity: toea without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&toea"
+                ]
+            ]
+        }, 
+        {
+            "input": "&toea;", 
+            "description": "Named entity: toea; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2928"
+                ]
+            ]
+        }, 
+        {
+            "input": "&top", 
+            "description": "Bad named entity: top without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&top"
+                ]
+            ]
+        }, 
+        {
+            "input": "&top;", 
+            "description": "Named entity: top; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topbot", 
+            "description": "Bad named entity: topbot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&topbot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topbot;", 
+            "description": "Named entity: topbot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2336"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topcir", 
+            "description": "Bad named entity: topcir without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&topcir"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topcir;", 
+            "description": "Named entity: topcir; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2af1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topf", 
+            "description": "Bad named entity: topf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&topf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topf;", 
+            "description": "Named entity: topf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd65"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topfork", 
+            "description": "Bad named entity: topfork without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&topfork"
+                ]
+            ]
+        }, 
+        {
+            "input": "&topfork;", 
+            "description": "Named entity: topfork; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ada"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tosa", 
+            "description": "Bad named entity: tosa without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tosa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tosa;", 
+            "description": "Named entity: tosa; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2929"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tprime", 
+            "description": "Bad named entity: tprime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tprime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tprime;", 
+            "description": "Named entity: tprime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2034"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trade", 
+            "description": "Bad named entity: trade without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&trade"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trade;", 
+            "description": "Named entity: trade; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2122"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangle", 
+            "description": "Bad named entity: triangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&triangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangle;", 
+            "description": "Named entity: triangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangledown", 
+            "description": "Bad named entity: triangledown without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&triangledown"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangledown;", 
+            "description": "Named entity: triangledown; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangleleft", 
+            "description": "Bad named entity: triangleleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&triangleleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangleleft;", 
+            "description": "Named entity: triangleleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trianglelefteq", 
+            "description": "Bad named entity: trianglelefteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&trianglelefteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trianglelefteq;", 
+            "description": "Named entity: trianglelefteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangleq", 
+            "description": "Bad named entity: triangleq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&triangleq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangleq;", 
+            "description": "Named entity: triangleq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u225c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangleright", 
+            "description": "Bad named entity: triangleright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&triangleright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triangleright;", 
+            "description": "Named entity: triangleright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trianglerighteq", 
+            "description": "Bad named entity: trianglerighteq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&trianglerighteq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trianglerighteq;", 
+            "description": "Named entity: trianglerighteq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tridot", 
+            "description": "Bad named entity: tridot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tridot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tridot;", 
+            "description": "Named entity: tridot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ec"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trie", 
+            "description": "Bad named entity: trie without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&trie"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trie;", 
+            "description": "Named entity: trie; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u225c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triminus", 
+            "description": "Bad named entity: triminus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&triminus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triminus;", 
+            "description": "Named entity: triminus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a3a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triplus", 
+            "description": "Bad named entity: triplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&triplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&triplus;", 
+            "description": "Named entity: triplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a39"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trisb", 
+            "description": "Bad named entity: trisb without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&trisb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trisb;", 
+            "description": "Named entity: trisb; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29cd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tritime", 
+            "description": "Bad named entity: tritime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tritime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tritime;", 
+            "description": "Named entity: tritime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a3b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trpezium", 
+            "description": "Bad named entity: trpezium without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&trpezium"
+                ]
+            ]
+        }, 
+        {
+            "input": "&trpezium;", 
+            "description": "Named entity: trpezium; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u23e2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tscr", 
+            "description": "Bad named entity: tscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tscr;", 
+            "description": "Named entity: tscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcc9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tscy", 
+            "description": "Bad named entity: tscy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tscy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tscy;", 
+            "description": "Named entity: tscy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0446"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tshcy", 
+            "description": "Bad named entity: tshcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tshcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tshcy;", 
+            "description": "Named entity: tshcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u045b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tstrok", 
+            "description": "Bad named entity: tstrok without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&tstrok"
+                ]
+            ]
+        }, 
+        {
+            "input": "&tstrok;", 
+            "description": "Named entity: tstrok; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0167"
+                ]
+            ]
+        }, 
+        {
+            "input": "&twixt", 
+            "description": "Bad named entity: twixt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&twixt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&twixt;", 
+            "description": "Named entity: twixt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u226c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&twoheadleftarrow", 
+            "description": "Bad named entity: twoheadleftarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&twoheadleftarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&twoheadleftarrow;", 
+            "description": "Named entity: twoheadleftarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u219e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&twoheadrightarrow", 
+            "description": "Bad named entity: twoheadrightarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&twoheadrightarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&twoheadrightarrow;", 
+            "description": "Named entity: twoheadrightarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21a0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uArr", 
+            "description": "Bad named entity: uArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uArr;", 
+            "description": "Named entity: uArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uHar", 
+            "description": "Bad named entity: uHar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uHar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uHar;", 
+            "description": "Named entity: uHar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2963"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uacute", 
+            "description": "Named entity: uacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00fa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uacute;", 
+            "description": "Named entity: uacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00fa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uarr", 
+            "description": "Bad named entity: uarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uarr;", 
+            "description": "Named entity: uarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2191"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ubrcy", 
+            "description": "Bad named entity: ubrcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ubrcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ubrcy;", 
+            "description": "Named entity: ubrcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u045e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ubreve", 
+            "description": "Bad named entity: ubreve without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ubreve"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ubreve;", 
+            "description": "Named entity: ubreve; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u016d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ucirc", 
+            "description": "Named entity: ucirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00fb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ucirc;", 
+            "description": "Named entity: ucirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00fb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ucy", 
+            "description": "Bad named entity: ucy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ucy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ucy;", 
+            "description": "Named entity: ucy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0443"
+                ]
+            ]
+        }, 
+        {
+            "input": "&udarr", 
+            "description": "Bad named entity: udarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&udarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&udarr;", 
+            "description": "Named entity: udarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&udblac", 
+            "description": "Bad named entity: udblac without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&udblac"
+                ]
+            ]
+        }, 
+        {
+            "input": "&udblac;", 
+            "description": "Named entity: udblac; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0171"
+                ]
+            ]
+        }, 
+        {
+            "input": "&udhar", 
+            "description": "Bad named entity: udhar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&udhar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&udhar;", 
+            "description": "Named entity: udhar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u296e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ufisht", 
+            "description": "Bad named entity: ufisht without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ufisht"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ufisht;", 
+            "description": "Named entity: ufisht; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u297e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ufr", 
+            "description": "Bad named entity: ufr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ufr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ufr;", 
+            "description": "Named entity: ufr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd32"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ugrave", 
+            "description": "Named entity: ugrave without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00f9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ugrave;", 
+            "description": "Named entity: ugrave; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00f9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uharl", 
+            "description": "Bad named entity: uharl without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uharl"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uharl;", 
+            "description": "Named entity: uharl; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uharr", 
+            "description": "Bad named entity: uharr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uharr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uharr;", 
+            "description": "Named entity: uharr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uhblk", 
+            "description": "Bad named entity: uhblk without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uhblk"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uhblk;", 
+            "description": "Named entity: uhblk; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2580"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ulcorn", 
+            "description": "Bad named entity: ulcorn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ulcorn"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ulcorn;", 
+            "description": "Named entity: ulcorn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ulcorner", 
+            "description": "Bad named entity: ulcorner without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ulcorner"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ulcorner;", 
+            "description": "Named entity: ulcorner; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ulcrop", 
+            "description": "Bad named entity: ulcrop without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ulcrop"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ulcrop;", 
+            "description": "Named entity: ulcrop; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ultri", 
+            "description": "Bad named entity: ultri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ultri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ultri;", 
+            "description": "Named entity: ultri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25f8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&umacr", 
+            "description": "Bad named entity: umacr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&umacr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&umacr;", 
+            "description": "Named entity: umacr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u016b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uml", 
+            "description": "Named entity: uml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uml;", 
+            "description": "Named entity: uml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uogon", 
+            "description": "Bad named entity: uogon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uogon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uogon;", 
+            "description": "Named entity: uogon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0173"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uopf", 
+            "description": "Bad named entity: uopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uopf;", 
+            "description": "Named entity: uopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd66"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uparrow", 
+            "description": "Bad named entity: uparrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uparrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uparrow;", 
+            "description": "Named entity: uparrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2191"
+                ]
+            ]
+        }, 
+        {
+            "input": "&updownarrow", 
+            "description": "Bad named entity: updownarrow without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&updownarrow"
+                ]
+            ]
+        }, 
+        {
+            "input": "&updownarrow;", 
+            "description": "Named entity: updownarrow; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2195"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upharpoonleft", 
+            "description": "Bad named entity: upharpoonleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&upharpoonleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upharpoonleft;", 
+            "description": "Named entity: upharpoonleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21bf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upharpoonright", 
+            "description": "Bad named entity: upharpoonright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&upharpoonright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upharpoonright;", 
+            "description": "Named entity: upharpoonright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uplus", 
+            "description": "Bad named entity: uplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uplus;", 
+            "description": "Named entity: uplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upsi", 
+            "description": "Bad named entity: upsi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&upsi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upsi;", 
+            "description": "Named entity: upsi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upsih", 
+            "description": "Bad named entity: upsih without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&upsih"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upsih;", 
+            "description": "Named entity: upsih; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upsilon", 
+            "description": "Bad named entity: upsilon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&upsilon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upsilon;", 
+            "description": "Named entity: upsilon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upuparrows", 
+            "description": "Bad named entity: upuparrows without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&upuparrows"
+                ]
+            ]
+        }, 
+        {
+            "input": "&upuparrows;", 
+            "description": "Named entity: upuparrows; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urcorn", 
+            "description": "Bad named entity: urcorn without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&urcorn"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urcorn;", 
+            "description": "Named entity: urcorn; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urcorner", 
+            "description": "Bad named entity: urcorner without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&urcorner"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urcorner;", 
+            "description": "Named entity: urcorner; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u231d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urcrop", 
+            "description": "Bad named entity: urcrop without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&urcrop"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urcrop;", 
+            "description": "Named entity: urcrop; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u230e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uring", 
+            "description": "Bad named entity: uring without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uring"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uring;", 
+            "description": "Named entity: uring; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u016f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urtri", 
+            "description": "Bad named entity: urtri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&urtri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&urtri;", 
+            "description": "Named entity: urtri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25f9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uscr", 
+            "description": "Bad named entity: uscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uscr;", 
+            "description": "Named entity: uscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcca"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utdot", 
+            "description": "Bad named entity: utdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&utdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utdot;", 
+            "description": "Named entity: utdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22f0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utilde", 
+            "description": "Bad named entity: utilde without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&utilde"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utilde;", 
+            "description": "Named entity: utilde; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0169"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utri", 
+            "description": "Bad named entity: utri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&utri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utri;", 
+            "description": "Named entity: utri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utrif", 
+            "description": "Bad named entity: utrif without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&utrif"
+                ]
+            ]
+        }, 
+        {
+            "input": "&utrif;", 
+            "description": "Named entity: utrif; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b4"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uuarr", 
+            "description": "Bad named entity: uuarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uuarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uuarr;", 
+            "description": "Named entity: uuarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21c8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uuml", 
+            "description": "Named entity: uuml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00fc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uuml;", 
+            "description": "Named entity: uuml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00fc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uwangle", 
+            "description": "Bad named entity: uwangle without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&uwangle"
+                ]
+            ]
+        }, 
+        {
+            "input": "&uwangle;", 
+            "description": "Named entity: uwangle; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u29a7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vArr", 
+            "description": "Bad named entity: vArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vArr;", 
+            "description": "Named entity: vArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vBar", 
+            "description": "Bad named entity: vBar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vBar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vBar;", 
+            "description": "Named entity: vBar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ae8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vBarv", 
+            "description": "Bad named entity: vBarv without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vBarv"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vBarv;", 
+            "description": "Named entity: vBarv; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2ae9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vDash", 
+            "description": "Bad named entity: vDash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vDash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vDash;", 
+            "description": "Named entity: vDash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vangrt", 
+            "description": "Bad named entity: vangrt without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vangrt"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vangrt;", 
+            "description": "Named entity: vangrt; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u299c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varepsilon", 
+            "description": "Bad named entity: varepsilon without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varepsilon"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varepsilon;", 
+            "description": "Named entity: varepsilon; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varkappa", 
+            "description": "Bad named entity: varkappa without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varkappa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varkappa;", 
+            "description": "Named entity: varkappa; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varnothing", 
+            "description": "Bad named entity: varnothing without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varnothing"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varnothing;", 
+            "description": "Named entity: varnothing; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2205"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varphi", 
+            "description": "Bad named entity: varphi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varphi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varphi;", 
+            "description": "Named entity: varphi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varpi", 
+            "description": "Bad named entity: varpi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varpi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varpi;", 
+            "description": "Named entity: varpi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varpropto", 
+            "description": "Bad named entity: varpropto without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varpropto"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varpropto;", 
+            "description": "Named entity: varpropto; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varr", 
+            "description": "Bad named entity: varr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varr;", 
+            "description": "Named entity: varr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2195"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varrho", 
+            "description": "Bad named entity: varrho without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varrho"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varrho;", 
+            "description": "Named entity: varrho; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03f1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsigma", 
+            "description": "Bad named entity: varsigma without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varsigma"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsigma;", 
+            "description": "Named entity: varsigma; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsubsetneq", 
+            "description": "Bad named entity: varsubsetneq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varsubsetneq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsubsetneq;", 
+            "description": "Named entity: varsubsetneq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228a\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsubsetneqq", 
+            "description": "Bad named entity: varsubsetneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varsubsetneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsubsetneqq;", 
+            "description": "Named entity: varsubsetneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acb\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsupsetneq", 
+            "description": "Bad named entity: varsupsetneq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varsupsetneq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsupsetneq;", 
+            "description": "Named entity: varsupsetneq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228b\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsupsetneqq", 
+            "description": "Bad named entity: varsupsetneqq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&varsupsetneqq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&varsupsetneqq;", 
+            "description": "Named entity: varsupsetneqq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acc\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vartheta", 
+            "description": "Bad named entity: vartheta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vartheta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vartheta;", 
+            "description": "Named entity: vartheta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03d1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vartriangleleft", 
+            "description": "Bad named entity: vartriangleleft without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vartriangleleft"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vartriangleleft;", 
+            "description": "Named entity: vartriangleleft; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vartriangleright", 
+            "description": "Bad named entity: vartriangleright without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vartriangleright"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vartriangleright;", 
+            "description": "Named entity: vartriangleright; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vcy", 
+            "description": "Bad named entity: vcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vcy;", 
+            "description": "Named entity: vcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0432"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vdash", 
+            "description": "Bad named entity: vdash without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vdash"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vdash;", 
+            "description": "Named entity: vdash; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22a2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vee", 
+            "description": "Bad named entity: vee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vee;", 
+            "description": "Named entity: vee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2228"
+                ]
+            ]
+        }, 
+        {
+            "input": "&veebar", 
+            "description": "Bad named entity: veebar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&veebar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&veebar;", 
+            "description": "Named entity: veebar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22bb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&veeeq", 
+            "description": "Bad named entity: veeeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&veeeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&veeeq;", 
+            "description": "Named entity: veeeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u225a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vellip", 
+            "description": "Bad named entity: vellip without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vellip"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vellip;", 
+            "description": "Named entity: vellip; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22ee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&verbar", 
+            "description": "Bad named entity: verbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&verbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&verbar;", 
+            "description": "Named entity: verbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "|"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vert", 
+            "description": "Bad named entity: vert without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vert"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vert;", 
+            "description": "Named entity: vert; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "|"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vfr", 
+            "description": "Bad named entity: vfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vfr;", 
+            "description": "Named entity: vfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd33"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vltri", 
+            "description": "Bad named entity: vltri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vltri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vltri;", 
+            "description": "Named entity: vltri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vnsub", 
+            "description": "Bad named entity: vnsub without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vnsub"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vnsub;", 
+            "description": "Named entity: vnsub; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2282\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vnsup", 
+            "description": "Bad named entity: vnsup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vnsup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vnsup;", 
+            "description": "Named entity: vnsup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2283\u20d2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vopf", 
+            "description": "Bad named entity: vopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vopf;", 
+            "description": "Named entity: vopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd67"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vprop", 
+            "description": "Bad named entity: vprop without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vprop"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vprop;", 
+            "description": "Named entity: vprop; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u221d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vrtri", 
+            "description": "Bad named entity: vrtri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vrtri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vrtri;", 
+            "description": "Named entity: vrtri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vscr", 
+            "description": "Bad named entity: vscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vscr;", 
+            "description": "Named entity: vscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udccb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsubnE", 
+            "description": "Bad named entity: vsubnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vsubnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsubnE;", 
+            "description": "Named entity: vsubnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acb\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsubne", 
+            "description": "Bad named entity: vsubne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vsubne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsubne;", 
+            "description": "Named entity: vsubne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228a\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsupnE", 
+            "description": "Bad named entity: vsupnE without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vsupnE"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsupnE;", 
+            "description": "Named entity: vsupnE; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2acc\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsupne", 
+            "description": "Bad named entity: vsupne without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vsupne"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vsupne;", 
+            "description": "Named entity: vsupne; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u228b\ufe00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vzigzag", 
+            "description": "Bad named entity: vzigzag without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&vzigzag"
+                ]
+            ]
+        }, 
+        {
+            "input": "&vzigzag;", 
+            "description": "Named entity: vzigzag; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u299a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wcirc", 
+            "description": "Bad named entity: wcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wcirc;", 
+            "description": "Named entity: wcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0175"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wedbar", 
+            "description": "Bad named entity: wedbar without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wedbar"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wedbar;", 
+            "description": "Named entity: wedbar; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a5f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wedge", 
+            "description": "Bad named entity: wedge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wedge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wedge;", 
+            "description": "Named entity: wedge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2227"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wedgeq", 
+            "description": "Bad named entity: wedgeq without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wedgeq"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wedgeq;", 
+            "description": "Named entity: wedgeq; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2259"
+                ]
+            ]
+        }, 
+        {
+            "input": "&weierp", 
+            "description": "Bad named entity: weierp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&weierp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&weierp;", 
+            "description": "Named entity: weierp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2118"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wfr", 
+            "description": "Bad named entity: wfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wfr;", 
+            "description": "Named entity: wfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd34"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wopf", 
+            "description": "Bad named entity: wopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wopf;", 
+            "description": "Named entity: wopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd68"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wp", 
+            "description": "Bad named entity: wp without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wp"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wp;", 
+            "description": "Named entity: wp; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2118"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wr", 
+            "description": "Bad named entity: wr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wr;", 
+            "description": "Named entity: wr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2240"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wreath", 
+            "description": "Bad named entity: wreath without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wreath"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wreath;", 
+            "description": "Named entity: wreath; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2240"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wscr", 
+            "description": "Bad named entity: wscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&wscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&wscr;", 
+            "description": "Named entity: wscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udccc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xcap", 
+            "description": "Bad named entity: xcap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xcap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xcap;", 
+            "description": "Named entity: xcap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c2"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xcirc", 
+            "description": "Bad named entity: xcirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xcirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xcirc;", 
+            "description": "Named entity: xcirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25ef"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xcup", 
+            "description": "Bad named entity: xcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xcup;", 
+            "description": "Named entity: xcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xdtri", 
+            "description": "Bad named entity: xdtri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xdtri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xdtri;", 
+            "description": "Named entity: xdtri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25bd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xfr", 
+            "description": "Bad named entity: xfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xfr;", 
+            "description": "Named entity: xfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd35"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xhArr", 
+            "description": "Bad named entity: xhArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xhArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xhArr;", 
+            "description": "Named entity: xhArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27fa"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xharr", 
+            "description": "Bad named entity: xharr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xharr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xharr;", 
+            "description": "Named entity: xharr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f7"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xi", 
+            "description": "Bad named entity: xi without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xi"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xi;", 
+            "description": "Named entity: xi; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03be"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xlArr", 
+            "description": "Bad named entity: xlArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xlArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xlArr;", 
+            "description": "Named entity: xlArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f8"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xlarr", 
+            "description": "Bad named entity: xlarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xlarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xlarr;", 
+            "description": "Named entity: xlarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xmap", 
+            "description": "Bad named entity: xmap without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xmap"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xmap;", 
+            "description": "Named entity: xmap; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27fc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xnis", 
+            "description": "Bad named entity: xnis without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xnis"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xnis;", 
+            "description": "Named entity: xnis; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22fb"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xodot", 
+            "description": "Bad named entity: xodot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xodot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xodot;", 
+            "description": "Named entity: xodot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a00"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xopf", 
+            "description": "Bad named entity: xopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xopf;", 
+            "description": "Named entity: xopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd69"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xoplus", 
+            "description": "Bad named entity: xoplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xoplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xoplus;", 
+            "description": "Named entity: xoplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a01"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xotime", 
+            "description": "Bad named entity: xotime without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xotime"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xotime;", 
+            "description": "Named entity: xotime; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a02"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xrArr", 
+            "description": "Bad named entity: xrArr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xrArr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xrArr;", 
+            "description": "Named entity: xrArr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f9"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xrarr", 
+            "description": "Bad named entity: xrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xrarr;", 
+            "description": "Named entity: xrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u27f6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xscr", 
+            "description": "Bad named entity: xscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xscr;", 
+            "description": "Named entity: xscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udccd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xsqcup", 
+            "description": "Bad named entity: xsqcup without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xsqcup"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xsqcup;", 
+            "description": "Named entity: xsqcup; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a06"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xuplus", 
+            "description": "Bad named entity: xuplus without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xuplus"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xuplus;", 
+            "description": "Named entity: xuplus; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2a04"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xutri", 
+            "description": "Bad named entity: xutri without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xutri"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xutri;", 
+            "description": "Named entity: xutri; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u25b3"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xvee", 
+            "description": "Bad named entity: xvee without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xvee"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xvee;", 
+            "description": "Named entity: xvee; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c1"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xwedge", 
+            "description": "Bad named entity: xwedge without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&xwedge"
+                ]
+            ]
+        }, 
+        {
+            "input": "&xwedge;", 
+            "description": "Named entity: xwedge; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u22c0"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yacute", 
+            "description": "Named entity: yacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00fd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yacute;", 
+            "description": "Named entity: yacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00fd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yacy", 
+            "description": "Bad named entity: yacy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&yacy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yacy;", 
+            "description": "Named entity: yacy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u044f"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ycirc", 
+            "description": "Bad named entity: ycirc without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ycirc"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ycirc;", 
+            "description": "Named entity: ycirc; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0177"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ycy", 
+            "description": "Bad named entity: ycy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&ycy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&ycy;", 
+            "description": "Named entity: ycy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u044b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yen", 
+            "description": "Named entity: yen without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yen;", 
+            "description": "Named entity: yen; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00a5"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yfr", 
+            "description": "Bad named entity: yfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&yfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yfr;", 
+            "description": "Named entity: yfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd36"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yicy", 
+            "description": "Bad named entity: yicy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&yicy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yicy;", 
+            "description": "Named entity: yicy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0457"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yopf", 
+            "description": "Bad named entity: yopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&yopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yopf;", 
+            "description": "Named entity: yopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd6a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yscr", 
+            "description": "Bad named entity: yscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&yscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yscr;", 
+            "description": "Named entity: yscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udcce"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yucy", 
+            "description": "Bad named entity: yucy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&yucy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yucy;", 
+            "description": "Named entity: yucy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u044e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yuml", 
+            "description": "Named entity: yuml without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "\u00ff"
+                ]
+            ]
+        }, 
+        {
+            "input": "&yuml;", 
+            "description": "Named entity: yuml; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u00ff"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zacute", 
+            "description": "Bad named entity: zacute without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zacute"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zacute;", 
+            "description": "Named entity: zacute; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u017a"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zcaron", 
+            "description": "Bad named entity: zcaron without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zcaron"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zcaron;", 
+            "description": "Named entity: zcaron; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u017e"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zcy", 
+            "description": "Bad named entity: zcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zcy;", 
+            "description": "Named entity: zcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0437"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zdot", 
+            "description": "Bad named entity: zdot without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zdot"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zdot;", 
+            "description": "Named entity: zdot; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u017c"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zeetrf", 
+            "description": "Bad named entity: zeetrf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zeetrf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zeetrf;", 
+            "description": "Named entity: zeetrf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u2128"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zeta", 
+            "description": "Bad named entity: zeta without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zeta"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zeta;", 
+            "description": "Named entity: zeta; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u03b6"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zfr", 
+            "description": "Bad named entity: zfr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zfr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zfr;", 
+            "description": "Named entity: zfr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd37"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zhcy", 
+            "description": "Bad named entity: zhcy without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zhcy"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zhcy;", 
+            "description": "Named entity: zhcy; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u0436"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zigrarr", 
+            "description": "Bad named entity: zigrarr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zigrarr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zigrarr;", 
+            "description": "Named entity: zigrarr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u21dd"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zopf", 
+            "description": "Bad named entity: zopf without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zopf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zopf;", 
+            "description": "Named entity: zopf; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udd6b"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zscr", 
+            "description": "Bad named entity: zscr without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zscr"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zscr;", 
+            "description": "Named entity: zscr; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\ud835\udccf"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zwj", 
+            "description": "Bad named entity: zwj without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zwj"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zwj;", 
+            "description": "Named entity: zwj; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200d"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zwnj", 
+            "description": "Bad named entity: zwnj without a semi-colon", 
+            "output": [
+                "ParseError", 
+                [
+                    "Character", 
+                    "&zwnj"
+                ]
+            ]
+        }, 
+        {
+            "input": "&zwnj;", 
+            "description": "Named entity: zwnj; with a semi-colon", 
+            "output": [
+                [
+                    "Character", 
+                    "\u200c"
+                ]
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/numericEntities.test b/pkg/third_party/html5lib/test/data/tokenizer/numericEntities.test
new file mode 100644
index 0000000..36c8228
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/numericEntities.test
@@ -0,0 +1,1313 @@
+{"tests": [
+
+{"description": "Invalid numeric entity character U+0000",
+"input": "&#x0000;",
+"output": ["ParseError", ["Character", "\uFFFD"]]},
+
+{"description": "Invalid numeric entity character U+0001",
+"input": "&#x0001;",
+"output": ["ParseError", ["Character", "\u0001"]]},
+
+{"description": "Invalid numeric entity character U+0002",
+"input": "&#x0002;",
+"output": ["ParseError", ["Character", "\u0002"]]},
+
+{"description": "Invalid numeric entity character U+0003",
+"input": "&#x0003;",
+"output": ["ParseError", ["Character", "\u0003"]]},
+
+{"description": "Invalid numeric entity character U+0004",
+"input": "&#x0004;",
+"output": ["ParseError", ["Character", "\u0004"]]},
+
+{"description": "Invalid numeric entity character U+0005",
+"input": "&#x0005;",
+"output": ["ParseError", ["Character", "\u0005"]]},
+
+{"description": "Invalid numeric entity character U+0006",
+"input": "&#x0006;",
+"output": ["ParseError", ["Character", "\u0006"]]},
+
+{"description": "Invalid numeric entity character U+0007",
+"input": "&#x0007;",
+"output": ["ParseError", ["Character", "\u0007"]]},
+
+{"description": "Invalid numeric entity character U+0008",
+"input": "&#x0008;",
+"output": ["ParseError", ["Character", "\u0008"]]},
+
+{"description": "Invalid numeric entity character U+000B",
+"input": "&#x000b;",
+"output": ["ParseError", ["Character", "\u000b"]]},
+
+{"description": "Invalid numeric entity character U+000E",
+"input": "&#x000e;",
+"output": ["ParseError", ["Character", "\u000e"]]},
+
+{"description": "Invalid numeric entity character U+000F",
+"input": "&#x000f;",
+"output": ["ParseError", ["Character", "\u000f"]]},
+
+{"description": "Invalid numeric entity character U+0010",
+"input": "&#x0010;",
+"output": ["ParseError", ["Character", "\u0010"]]},
+
+{"description": "Invalid numeric entity character U+0011",
+"input": "&#x0011;",
+"output": ["ParseError", ["Character", "\u0011"]]},
+
+{"description": "Invalid numeric entity character U+0012",
+"input": "&#x0012;",
+"output": ["ParseError", ["Character", "\u0012"]]},
+
+{"description": "Invalid numeric entity character U+0013",
+"input": "&#x0013;",
+"output": ["ParseError", ["Character", "\u0013"]]},
+
+{"description": "Invalid numeric entity character U+0014",
+"input": "&#x0014;",
+"output": ["ParseError", ["Character", "\u0014"]]},
+
+{"description": "Invalid numeric entity character U+0015",
+"input": "&#x0015;",
+"output": ["ParseError", ["Character", "\u0015"]]},
+
+{"description": "Invalid numeric entity character U+0016",
+"input": "&#x0016;",
+"output": ["ParseError", ["Character", "\u0016"]]},
+
+{"description": "Invalid numeric entity character U+0017",
+"input": "&#x0017;",
+"output": ["ParseError", ["Character", "\u0017"]]},
+
+{"description": "Invalid numeric entity character U+0018",
+"input": "&#x0018;",
+"output": ["ParseError", ["Character", "\u0018"]]},
+
+{"description": "Invalid numeric entity character U+0019",
+"input": "&#x0019;",
+"output": ["ParseError", ["Character", "\u0019"]]},
+
+{"description": "Invalid numeric entity character U+001A",
+"input": "&#x001a;",
+"output": ["ParseError", ["Character", "\u001a"]]},
+
+{"description": "Invalid numeric entity character U+001B",
+"input": "&#x001b;",
+"output": ["ParseError", ["Character", "\u001b"]]},
+
+{"description": "Invalid numeric entity character U+001C",
+"input": "&#x001c;",
+"output": ["ParseError", ["Character", "\u001c"]]},
+
+{"description": "Invalid numeric entity character U+001D",
+"input": "&#x001d;",
+"output": ["ParseError", ["Character", "\u001d"]]},
+
+{"description": "Invalid numeric entity character U+001E",
+"input": "&#x001e;",
+"output": ["ParseError", ["Character", "\u001e"]]},
+
+{"description": "Invalid numeric entity character U+001F",
+"input": "&#x001f;",
+"output": ["ParseError", ["Character", "\u001f"]]},
+
+{"description": "Invalid numeric entity character U+007F",
+"input": "&#x007f;",
+"output": ["ParseError", ["Character", "\u007f"]]},
+
+{"description": "Invalid numeric entity character U+D800",
+"input": "&#xd800;",
+"output": ["ParseError", ["Character", "\uFFFD"]]},
+
+{"description": "Invalid numeric entity character U+DFFF",
+"input": "&#xdfff;",
+"output": ["ParseError", ["Character", "\uFFFD"]]},
+
+{"description": "Invalid numeric entity character U+FDD0",
+"input": "&#xfdd0;",
+"output": ["ParseError", ["Character", "\ufdd0"]]},
+
+{"description": "Invalid numeric entity character U+FDD1",
+"input": "&#xfdd1;",
+"output": ["ParseError", ["Character", "\ufdd1"]]},
+
+{"description": "Invalid numeric entity character U+FDD2",
+"input": "&#xfdd2;",
+"output": ["ParseError", ["Character", "\ufdd2"]]},
+
+{"description": "Invalid numeric entity character U+FDD3",
+"input": "&#xfdd3;",
+"output": ["ParseError", ["Character", "\ufdd3"]]},
+
+{"description": "Invalid numeric entity character U+FDD4",
+"input": "&#xfdd4;",
+"output": ["ParseError", ["Character", "\ufdd4"]]},
+
+{"description": "Invalid numeric entity character U+FDD5",
+"input": "&#xfdd5;",
+"output": ["ParseError", ["Character", "\ufdd5"]]},
+
+{"description": "Invalid numeric entity character U+FDD6",
+"input": "&#xfdd6;",
+"output": ["ParseError", ["Character", "\ufdd6"]]},
+
+{"description": "Invalid numeric entity character U+FDD7",
+"input": "&#xfdd7;",
+"output": ["ParseError", ["Character", "\ufdd7"]]},
+
+{"description": "Invalid numeric entity character U+FDD8",
+"input": "&#xfdd8;",
+"output": ["ParseError", ["Character", "\ufdd8"]]},
+
+{"description": "Invalid numeric entity character U+FDD9",
+"input": "&#xfdd9;",
+"output": ["ParseError", ["Character", "\ufdd9"]]},
+
+{"description": "Invalid numeric entity character U+FDDA",
+"input": "&#xfdda;",
+"output": ["ParseError", ["Character", "\ufdda"]]},
+
+{"description": "Invalid numeric entity character U+FDDB",
+"input": "&#xfddb;",
+"output": ["ParseError", ["Character", "\ufddb"]]},
+
+{"description": "Invalid numeric entity character U+FDDC",
+"input": "&#xfddc;",
+"output": ["ParseError", ["Character", "\ufddc"]]},
+
+{"description": "Invalid numeric entity character U+FDDD",
+"input": "&#xfddd;",
+"output": ["ParseError", ["Character", "\ufddd"]]},
+
+{"description": "Invalid numeric entity character U+FDDE",
+"input": "&#xfdde;",
+"output": ["ParseError", ["Character", "\ufdde"]]},
+
+{"description": "Invalid numeric entity character U+FDDF",
+"input": "&#xfddf;",
+"output": ["ParseError", ["Character", "\ufddf"]]},
+
+{"description": "Invalid numeric entity character U+FDE0",
+"input": "&#xfde0;",
+"output": ["ParseError", ["Character", "\ufde0"]]},
+
+{"description": "Invalid numeric entity character U+FDE1",
+"input": "&#xfde1;",
+"output": ["ParseError", ["Character", "\ufde1"]]},
+
+{"description": "Invalid numeric entity character U+FDE2",
+"input": "&#xfde2;",
+"output": ["ParseError", ["Character", "\ufde2"]]},
+
+{"description": "Invalid numeric entity character U+FDE3",
+"input": "&#xfde3;",
+"output": ["ParseError", ["Character", "\ufde3"]]},
+
+{"description": "Invalid numeric entity character U+FDE4",
+"input": "&#xfde4;",
+"output": ["ParseError", ["Character", "\ufde4"]]},
+
+{"description": "Invalid numeric entity character U+FDE5",
+"input": "&#xfde5;",
+"output": ["ParseError", ["Character", "\ufde5"]]},
+
+{"description": "Invalid numeric entity character U+FDE6",
+"input": "&#xfde6;",
+"output": ["ParseError", ["Character", "\ufde6"]]},
+
+{"description": "Invalid numeric entity character U+FDE7",
+"input": "&#xfde7;",
+"output": ["ParseError", ["Character", "\ufde7"]]},
+
+{"description": "Invalid numeric entity character U+FDE8",
+"input": "&#xfde8;",
+"output": ["ParseError", ["Character", "\ufde8"]]},
+
+{"description": "Invalid numeric entity character U+FDE9",
+"input": "&#xfde9;",
+"output": ["ParseError", ["Character", "\ufde9"]]},
+
+{"description": "Invalid numeric entity character U+FDEA",
+"input": "&#xfdea;",
+"output": ["ParseError", ["Character", "\ufdea"]]},
+
+{"description": "Invalid numeric entity character U+FDEB",
+"input": "&#xfdeb;",
+"output": ["ParseError", ["Character", "\ufdeb"]]},
+
+{"description": "Invalid numeric entity character U+FDEC",
+"input": "&#xfdec;",
+"output": ["ParseError", ["Character", "\ufdec"]]},
+
+{"description": "Invalid numeric entity character U+FDED",
+"input": "&#xfded;",
+"output": ["ParseError", ["Character", "\ufded"]]},
+
+{"description": "Invalid numeric entity character U+FDEE",
+"input": "&#xfdee;",
+"output": ["ParseError", ["Character", "\ufdee"]]},
+
+{"description": "Invalid numeric entity character U+FDEF",
+"input": "&#xfdef;",
+"output": ["ParseError", ["Character", "\ufdef"]]},
+
+{"description": "Invalid numeric entity character U+FFFE",
+"input": "&#xfffe;",
+"output": ["ParseError", ["Character", "\ufffe"]]},
+
+{"description": "Invalid numeric entity character U+FFFF",
+"input": "&#xffff;",
+"output": ["ParseError", ["Character", "\uffff"]]},
+
+{"description": "Invalid numeric entity character U+1FFFE",
+"input": "&#x1fffe;",
+"output": ["ParseError", ["Character", "\uD83F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+1FFFF",
+"input": "&#x1ffff;",
+"output": ["ParseError", ["Character", "\uD83F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+2FFFE",
+"input": "&#x2fffe;",
+"output": ["ParseError", ["Character", "\uD87F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+2FFFF",
+"input": "&#x2ffff;",
+"output": ["ParseError", ["Character", "\uD87F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+3FFFE",
+"input": "&#x3fffe;",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+3FFFF",
+"input": "&#x3ffff;",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+4FFFE",
+"input": "&#x4fffe;",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+4FFFF",
+"input": "&#x4ffff;",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+5FFFE",
+"input": "&#x5fffe;",
+"output": ["ParseError", ["Character", "\uD93F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+5FFFF",
+"input": "&#x5ffff;",
+"output": ["ParseError", ["Character", "\uD93F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+6FFFE",
+"input": "&#x6fffe;",
+"output": ["ParseError", ["Character", "\uD97F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+6FFFF",
+"input": "&#x6ffff;",
+"output": ["ParseError", ["Character", "\uD97F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+7FFFE",
+"input": "&#x7fffe;",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+7FFFF",
+"input": "&#x7ffff;",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+8FFFE",
+"input": "&#x8fffe;",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+8FFFF",
+"input": "&#x8ffff;",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+9FFFE",
+"input": "&#x9fffe;",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+9FFFF",
+"input": "&#x9ffff;",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+AFFFE",
+"input": "&#xafffe;",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+AFFFF",
+"input": "&#xaffff;",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+BFFFE",
+"input": "&#xbfffe;",
+"output": ["ParseError", ["Character", "\uDABF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+BFFFF",
+"input": "&#xbffff;",
+"output": ["ParseError", ["Character", "\uDABF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+CFFFE",
+"input": "&#xcfffe;",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+CFFFF",
+"input": "&#xcffff;",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+DFFFE",
+"input": "&#xdfffe;",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+DFFFF",
+"input": "&#xdffff;",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+EFFFE",
+"input": "&#xefffe;",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+EFFFF",
+"input": "&#xeffff;",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+FFFFE",
+"input": "&#xffffe;",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+FFFFF",
+"input": "&#xfffff;",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+10FFFE",
+"input": "&#x10fffe;",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+10FFFF",
+"input": "&#x10ffff;",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFF"]]},
+
+{"description": "Valid numeric entity character U+0009",
+"input": "&#x0009;",
+"output": [["Character", "\u0009"]]},
+
+{"description": "Valid numeric entity character U+000A",
+"input": "&#x000a;",
+"output": [["Character", "\u000A"]]},
+
+{"description": "Valid numeric entity character U+0020",
+"input": "&#x0020;",
+"output": [["Character", "\u0020"]]},
+
+{"description": "Valid numeric entity character U+0021",
+"input": "&#x0021;",
+"output": [["Character", "\u0021"]]},
+
+{"description": "Valid numeric entity character U+0022",
+"input": "&#x0022;",
+"output": [["Character", "\u0022"]]},
+
+{"description": "Valid numeric entity character U+0023",
+"input": "&#x0023;",
+"output": [["Character", "\u0023"]]},
+
+{"description": "Valid numeric entity character U+0024",
+"input": "&#x0024;",
+"output": [["Character", "\u0024"]]},
+
+{"description": "Valid numeric entity character U+0025",
+"input": "&#x0025;",
+"output": [["Character", "\u0025"]]},
+
+{"description": "Valid numeric entity character U+0026",
+"input": "&#x0026;",
+"output": [["Character", "\u0026"]]},
+
+{"description": "Valid numeric entity character U+0027",
+"input": "&#x0027;",
+"output": [["Character", "\u0027"]]},
+
+{"description": "Valid numeric entity character U+0028",
+"input": "&#x0028;",
+"output": [["Character", "\u0028"]]},
+
+{"description": "Valid numeric entity character U+0029",
+"input": "&#x0029;",
+"output": [["Character", "\u0029"]]},
+
+{"description": "Valid numeric entity character U+002A",
+"input": "&#x002a;",
+"output": [["Character", "\u002A"]]},
+
+{"description": "Valid numeric entity character U+002B",
+"input": "&#x002b;",
+"output": [["Character", "\u002B"]]},
+
+{"description": "Valid numeric entity character U+002C",
+"input": "&#x002c;",
+"output": [["Character", "\u002C"]]},
+
+{"description": "Valid numeric entity character U+002D",
+"input": "&#x002d;",
+"output": [["Character", "\u002D"]]},
+
+{"description": "Valid numeric entity character U+002E",
+"input": "&#x002e;",
+"output": [["Character", "\u002E"]]},
+
+{"description": "Valid numeric entity character U+002F",
+"input": "&#x002f;",
+"output": [["Character", "\u002F"]]},
+
+{"description": "Valid numeric entity character U+0030",
+"input": "&#x0030;",
+"output": [["Character", "\u0030"]]},
+
+{"description": "Valid numeric entity character U+0031",
+"input": "&#x0031;",
+"output": [["Character", "\u0031"]]},
+
+{"description": "Valid numeric entity character U+0032",
+"input": "&#x0032;",
+"output": [["Character", "\u0032"]]},
+
+{"description": "Valid numeric entity character U+0033",
+"input": "&#x0033;",
+"output": [["Character", "\u0033"]]},
+
+{"description": "Valid numeric entity character U+0034",
+"input": "&#x0034;",
+"output": [["Character", "\u0034"]]},
+
+{"description": "Valid numeric entity character U+0035",
+"input": "&#x0035;",
+"output": [["Character", "\u0035"]]},
+
+{"description": "Valid numeric entity character U+0036",
+"input": "&#x0036;",
+"output": [["Character", "\u0036"]]},
+
+{"description": "Valid numeric entity character U+0037",
+"input": "&#x0037;",
+"output": [["Character", "\u0037"]]},
+
+{"description": "Valid numeric entity character U+0038",
+"input": "&#x0038;",
+"output": [["Character", "\u0038"]]},
+
+{"description": "Valid numeric entity character U+0039",
+"input": "&#x0039;",
+"output": [["Character", "\u0039"]]},
+
+{"description": "Valid numeric entity character U+003A",
+"input": "&#x003a;",
+"output": [["Character", "\u003A"]]},
+
+{"description": "Valid numeric entity character U+003B",
+"input": "&#x003b;",
+"output": [["Character", "\u003B"]]},
+
+{"description": "Valid numeric entity character U+003C",
+"input": "&#x003c;",
+"output": [["Character", "\u003C"]]},
+
+{"description": "Valid numeric entity character U+003D",
+"input": "&#x003d;",
+"output": [["Character", "\u003D"]]},
+
+{"description": "Valid numeric entity character U+003E",
+"input": "&#x003e;",
+"output": [["Character", "\u003E"]]},
+
+{"description": "Valid numeric entity character U+003F",
+"input": "&#x003f;",
+"output": [["Character", "\u003F"]]},
+
+{"description": "Valid numeric entity character U+0040",
+"input": "&#x0040;",
+"output": [["Character", "\u0040"]]},
+
+{"description": "Valid numeric entity character U+0041",
+"input": "&#x0041;",
+"output": [["Character", "\u0041"]]},
+
+{"description": "Valid numeric entity character U+0042",
+"input": "&#x0042;",
+"output": [["Character", "\u0042"]]},
+
+{"description": "Valid numeric entity character U+0043",
+"input": "&#x0043;",
+"output": [["Character", "\u0043"]]},
+
+{"description": "Valid numeric entity character U+0044",
+"input": "&#x0044;",
+"output": [["Character", "\u0044"]]},
+
+{"description": "Valid numeric entity character U+0045",
+"input": "&#x0045;",
+"output": [["Character", "\u0045"]]},
+
+{"description": "Valid numeric entity character U+0046",
+"input": "&#x0046;",
+"output": [["Character", "\u0046"]]},
+
+{"description": "Valid numeric entity character U+0047",
+"input": "&#x0047;",
+"output": [["Character", "\u0047"]]},
+
+{"description": "Valid numeric entity character U+0048",
+"input": "&#x0048;",
+"output": [["Character", "\u0048"]]},
+
+{"description": "Valid numeric entity character U+0049",
+"input": "&#x0049;",
+"output": [["Character", "\u0049"]]},
+
+{"description": "Valid numeric entity character U+004A",
+"input": "&#x004a;",
+"output": [["Character", "\u004A"]]},
+
+{"description": "Valid numeric entity character U+004B",
+"input": "&#x004b;",
+"output": [["Character", "\u004B"]]},
+
+{"description": "Valid numeric entity character U+004C",
+"input": "&#x004c;",
+"output": [["Character", "\u004C"]]},
+
+{"description": "Valid numeric entity character U+004D",
+"input": "&#x004d;",
+"output": [["Character", "\u004D"]]},
+
+{"description": "Valid numeric entity character U+004E",
+"input": "&#x004e;",
+"output": [["Character", "\u004E"]]},
+
+{"description": "Valid numeric entity character U+004F",
+"input": "&#x004f;",
+"output": [["Character", "\u004F"]]},
+
+{"description": "Valid numeric entity character U+0050",
+"input": "&#x0050;",
+"output": [["Character", "\u0050"]]},
+
+{"description": "Valid numeric entity character U+0051",
+"input": "&#x0051;",
+"output": [["Character", "\u0051"]]},
+
+{"description": "Valid numeric entity character U+0052",
+"input": "&#x0052;",
+"output": [["Character", "\u0052"]]},
+
+{"description": "Valid numeric entity character U+0053",
+"input": "&#x0053;",
+"output": [["Character", "\u0053"]]},
+
+{"description": "Valid numeric entity character U+0054",
+"input": "&#x0054;",
+"output": [["Character", "\u0054"]]},
+
+{"description": "Valid numeric entity character U+0055",
+"input": "&#x0055;",
+"output": [["Character", "\u0055"]]},
+
+{"description": "Valid numeric entity character U+0056",
+"input": "&#x0056;",
+"output": [["Character", "\u0056"]]},
+
+{"description": "Valid numeric entity character U+0057",
+"input": "&#x0057;",
+"output": [["Character", "\u0057"]]},
+
+{"description": "Valid numeric entity character U+0058",
+"input": "&#x0058;",
+"output": [["Character", "\u0058"]]},
+
+{"description": "Valid numeric entity character U+0059",
+"input": "&#x0059;",
+"output": [["Character", "\u0059"]]},
+
+{"description": "Valid numeric entity character U+005A",
+"input": "&#x005a;",
+"output": [["Character", "\u005A"]]},
+
+{"description": "Valid numeric entity character U+005B",
+"input": "&#x005b;",
+"output": [["Character", "\u005B"]]},
+
+{"description": "Valid numeric entity character U+005C",
+"input": "&#x005c;",
+"output": [["Character", "\u005C"]]},
+
+{"description": "Valid numeric entity character U+005D",
+"input": "&#x005d;",
+"output": [["Character", "\u005D"]]},
+
+{"description": "Valid numeric entity character U+005E",
+"input": "&#x005e;",
+"output": [["Character", "\u005E"]]},
+
+{"description": "Valid numeric entity character U+005F",
+"input": "&#x005f;",
+"output": [["Character", "\u005F"]]},
+
+{"description": "Valid numeric entity character U+0060",
+"input": "&#x0060;",
+"output": [["Character", "\u0060"]]},
+
+{"description": "Valid numeric entity character U+0061",
+"input": "&#x0061;",
+"output": [["Character", "\u0061"]]},
+
+{"description": "Valid numeric entity character U+0062",
+"input": "&#x0062;",
+"output": [["Character", "\u0062"]]},
+
+{"description": "Valid numeric entity character U+0063",
+"input": "&#x0063;",
+"output": [["Character", "\u0063"]]},
+
+{"description": "Valid numeric entity character U+0064",
+"input": "&#x0064;",
+"output": [["Character", "\u0064"]]},
+
+{"description": "Valid numeric entity character U+0065",
+"input": "&#x0065;",
+"output": [["Character", "\u0065"]]},
+
+{"description": "Valid numeric entity character U+0066",
+"input": "&#x0066;",
+"output": [["Character", "\u0066"]]},
+
+{"description": "Valid numeric entity character U+0067",
+"input": "&#x0067;",
+"output": [["Character", "\u0067"]]},
+
+{"description": "Valid numeric entity character U+0068",
+"input": "&#x0068;",
+"output": [["Character", "\u0068"]]},
+
+{"description": "Valid numeric entity character U+0069",
+"input": "&#x0069;",
+"output": [["Character", "\u0069"]]},
+
+{"description": "Valid numeric entity character U+006A",
+"input": "&#x006a;",
+"output": [["Character", "\u006A"]]},
+
+{"description": "Valid numeric entity character U+006B",
+"input": "&#x006b;",
+"output": [["Character", "\u006B"]]},
+
+{"description": "Valid numeric entity character U+006C",
+"input": "&#x006c;",
+"output": [["Character", "\u006C"]]},
+
+{"description": "Valid numeric entity character U+006D",
+"input": "&#x006d;",
+"output": [["Character", "\u006D"]]},
+
+{"description": "Valid numeric entity character U+006E",
+"input": "&#x006e;",
+"output": [["Character", "\u006E"]]},
+
+{"description": "Valid numeric entity character U+006F",
+"input": "&#x006f;",
+"output": [["Character", "\u006F"]]},
+
+{"description": "Valid numeric entity character U+0070",
+"input": "&#x0070;",
+"output": [["Character", "\u0070"]]},
+
+{"description": "Valid numeric entity character U+0071",
+"input": "&#x0071;",
+"output": [["Character", "\u0071"]]},
+
+{"description": "Valid numeric entity character U+0072",
+"input": "&#x0072;",
+"output": [["Character", "\u0072"]]},
+
+{"description": "Valid numeric entity character U+0073",
+"input": "&#x0073;",
+"output": [["Character", "\u0073"]]},
+
+{"description": "Valid numeric entity character U+0074",
+"input": "&#x0074;",
+"output": [["Character", "\u0074"]]},
+
+{"description": "Valid numeric entity character U+0075",
+"input": "&#x0075;",
+"output": [["Character", "\u0075"]]},
+
+{"description": "Valid numeric entity character U+0076",
+"input": "&#x0076;",
+"output": [["Character", "\u0076"]]},
+
+{"description": "Valid numeric entity character U+0077",
+"input": "&#x0077;",
+"output": [["Character", "\u0077"]]},
+
+{"description": "Valid numeric entity character U+0078",
+"input": "&#x0078;",
+"output": [["Character", "\u0078"]]},
+
+{"description": "Valid numeric entity character U+0079",
+"input": "&#x0079;",
+"output": [["Character", "\u0079"]]},
+
+{"description": "Valid numeric entity character U+007A",
+"input": "&#x007a;",
+"output": [["Character", "\u007A"]]},
+
+{"description": "Valid numeric entity character U+007B",
+"input": "&#x007b;",
+"output": [["Character", "\u007B"]]},
+
+{"description": "Valid numeric entity character U+007C",
+"input": "&#x007c;",
+"output": [["Character", "\u007C"]]},
+
+{"description": "Valid numeric entity character U+007D",
+"input": "&#x007d;",
+"output": [["Character", "\u007D"]]},
+
+{"description": "Valid numeric entity character U+007E",
+"input": "&#x007e;",
+"output": [["Character", "\u007E"]]},
+
+{"description": "Valid numeric entity character U+00A0",
+"input": "&#x00a0;",
+"output": [["Character", "\u00A0"]]},
+
+{"description": "Valid numeric entity character U+00A1",
+"input": "&#x00a1;",
+"output": [["Character", "\u00A1"]]},
+
+{"description": "Valid numeric entity character U+00A2",
+"input": "&#x00a2;",
+"output": [["Character", "\u00A2"]]},
+
+{"description": "Valid numeric entity character U+00A3",
+"input": "&#x00a3;",
+"output": [["Character", "\u00A3"]]},
+
+{"description": "Valid numeric entity character U+00A4",
+"input": "&#x00a4;",
+"output": [["Character", "\u00A4"]]},
+
+{"description": "Valid numeric entity character U+00A5",
+"input": "&#x00a5;",
+"output": [["Character", "\u00A5"]]},
+
+{"description": "Valid numeric entity character U+00A6",
+"input": "&#x00a6;",
+"output": [["Character", "\u00A6"]]},
+
+{"description": "Valid numeric entity character U+00A7",
+"input": "&#x00a7;",
+"output": [["Character", "\u00A7"]]},
+
+{"description": "Valid numeric entity character U+00A8",
+"input": "&#x00a8;",
+"output": [["Character", "\u00A8"]]},
+
+{"description": "Valid numeric entity character U+00A9",
+"input": "&#x00a9;",
+"output": [["Character", "\u00A9"]]},
+
+{"description": "Valid numeric entity character U+00AA",
+"input": "&#x00aa;",
+"output": [["Character", "\u00AA"]]},
+
+{"description": "Valid numeric entity character U+00AB",
+"input": "&#x00ab;",
+"output": [["Character", "\u00AB"]]},
+
+{"description": "Valid numeric entity character U+00AC",
+"input": "&#x00ac;",
+"output": [["Character", "\u00AC"]]},
+
+{"description": "Valid numeric entity character U+00AD",
+"input": "&#x00ad;",
+"output": [["Character", "\u00AD"]]},
+
+{"description": "Valid numeric entity character U+00AE",
+"input": "&#x00ae;",
+"output": [["Character", "\u00AE"]]},
+
+{"description": "Valid numeric entity character U+00AF",
+"input": "&#x00af;",
+"output": [["Character", "\u00AF"]]},
+
+{"description": "Valid numeric entity character U+00B0",
+"input": "&#x00b0;",
+"output": [["Character", "\u00B0"]]},
+
+{"description": "Valid numeric entity character U+00B1",
+"input": "&#x00b1;",
+"output": [["Character", "\u00B1"]]},
+
+{"description": "Valid numeric entity character U+00B2",
+"input": "&#x00b2;",
+"output": [["Character", "\u00B2"]]},
+
+{"description": "Valid numeric entity character U+00B3",
+"input": "&#x00b3;",
+"output": [["Character", "\u00B3"]]},
+
+{"description": "Valid numeric entity character U+00B4",
+"input": "&#x00b4;",
+"output": [["Character", "\u00B4"]]},
+
+{"description": "Valid numeric entity character U+00B5",
+"input": "&#x00b5;",
+"output": [["Character", "\u00B5"]]},
+
+{"description": "Valid numeric entity character U+00B6",
+"input": "&#x00b6;",
+"output": [["Character", "\u00B6"]]},
+
+{"description": "Valid numeric entity character U+00B7",
+"input": "&#x00b7;",
+"output": [["Character", "\u00B7"]]},
+
+{"description": "Valid numeric entity character U+00B8",
+"input": "&#x00b8;",
+"output": [["Character", "\u00B8"]]},
+
+{"description": "Valid numeric entity character U+00B9",
+"input": "&#x00b9;",
+"output": [["Character", "\u00B9"]]},
+
+{"description": "Valid numeric entity character U+00BA",
+"input": "&#x00ba;",
+"output": [["Character", "\u00BA"]]},
+
+{"description": "Valid numeric entity character U+00BB",
+"input": "&#x00bb;",
+"output": [["Character", "\u00BB"]]},
+
+{"description": "Valid numeric entity character U+00BC",
+"input": "&#x00bc;",
+"output": [["Character", "\u00BC"]]},
+
+{"description": "Valid numeric entity character U+00BD",
+"input": "&#x00bd;",
+"output": [["Character", "\u00BD"]]},
+
+{"description": "Valid numeric entity character U+00BE",
+"input": "&#x00be;",
+"output": [["Character", "\u00BE"]]},
+
+{"description": "Valid numeric entity character U+00BF",
+"input": "&#x00bf;",
+"output": [["Character", "\u00BF"]]},
+
+{"description": "Valid numeric entity character U+00C0",
+"input": "&#x00c0;",
+"output": [["Character", "\u00C0"]]},
+
+{"description": "Valid numeric entity character U+00C1",
+"input": "&#x00c1;",
+"output": [["Character", "\u00C1"]]},
+
+{"description": "Valid numeric entity character U+00C2",
+"input": "&#x00c2;",
+"output": [["Character", "\u00C2"]]},
+
+{"description": "Valid numeric entity character U+00C3",
+"input": "&#x00c3;",
+"output": [["Character", "\u00C3"]]},
+
+{"description": "Valid numeric entity character U+00C4",
+"input": "&#x00c4;",
+"output": [["Character", "\u00C4"]]},
+
+{"description": "Valid numeric entity character U+00C5",
+"input": "&#x00c5;",
+"output": [["Character", "\u00C5"]]},
+
+{"description": "Valid numeric entity character U+00C6",
+"input": "&#x00c6;",
+"output": [["Character", "\u00C6"]]},
+
+{"description": "Valid numeric entity character U+00C7",
+"input": "&#x00c7;",
+"output": [["Character", "\u00C7"]]},
+
+{"description": "Valid numeric entity character U+00C8",
+"input": "&#x00c8;",
+"output": [["Character", "\u00C8"]]},
+
+{"description": "Valid numeric entity character U+00C9",
+"input": "&#x00c9;",
+"output": [["Character", "\u00C9"]]},
+
+{"description": "Valid numeric entity character U+00CA",
+"input": "&#x00ca;",
+"output": [["Character", "\u00CA"]]},
+
+{"description": "Valid numeric entity character U+00CB",
+"input": "&#x00cb;",
+"output": [["Character", "\u00CB"]]},
+
+{"description": "Valid numeric entity character U+00CC",
+"input": "&#x00cc;",
+"output": [["Character", "\u00CC"]]},
+
+{"description": "Valid numeric entity character U+00CD",
+"input": "&#x00cd;",
+"output": [["Character", "\u00CD"]]},
+
+{"description": "Valid numeric entity character U+00CE",
+"input": "&#x00ce;",
+"output": [["Character", "\u00CE"]]},
+
+{"description": "Valid numeric entity character U+00CF",
+"input": "&#x00cf;",
+"output": [["Character", "\u00CF"]]},
+
+{"description": "Valid numeric entity character U+00D0",
+"input": "&#x00d0;",
+"output": [["Character", "\u00D0"]]},
+
+{"description": "Valid numeric entity character U+00D1",
+"input": "&#x00d1;",
+"output": [["Character", "\u00D1"]]},
+
+{"description": "Valid numeric entity character U+00D2",
+"input": "&#x00d2;",
+"output": [["Character", "\u00D2"]]},
+
+{"description": "Valid numeric entity character U+00D3",
+"input": "&#x00d3;",
+"output": [["Character", "\u00D3"]]},
+
+{"description": "Valid numeric entity character U+00D4",
+"input": "&#x00d4;",
+"output": [["Character", "\u00D4"]]},
+
+{"description": "Valid numeric entity character U+00D5",
+"input": "&#x00d5;",
+"output": [["Character", "\u00D5"]]},
+
+{"description": "Valid numeric entity character U+00D6",
+"input": "&#x00d6;",
+"output": [["Character", "\u00D6"]]},
+
+{"description": "Valid numeric entity character U+00D7",
+"input": "&#x00d7;",
+"output": [["Character", "\u00D7"]]},
+
+{"description": "Valid numeric entity character U+00D8",
+"input": "&#x00d8;",
+"output": [["Character", "\u00D8"]]},
+
+{"description": "Valid numeric entity character U+00D9",
+"input": "&#x00d9;",
+"output": [["Character", "\u00D9"]]},
+
+{"description": "Valid numeric entity character U+00DA",
+"input": "&#x00da;",
+"output": [["Character", "\u00DA"]]},
+
+{"description": "Valid numeric entity character U+00DB",
+"input": "&#x00db;",
+"output": [["Character", "\u00DB"]]},
+
+{"description": "Valid numeric entity character U+00DC",
+"input": "&#x00dc;",
+"output": [["Character", "\u00DC"]]},
+
+{"description": "Valid numeric entity character U+00DD",
+"input": "&#x00dd;",
+"output": [["Character", "\u00DD"]]},
+
+{"description": "Valid numeric entity character U+00DE",
+"input": "&#x00de;",
+"output": [["Character", "\u00DE"]]},
+
+{"description": "Valid numeric entity character U+00DF",
+"input": "&#x00df;",
+"output": [["Character", "\u00DF"]]},
+
+{"description": "Valid numeric entity character U+00E0",
+"input": "&#x00e0;",
+"output": [["Character", "\u00E0"]]},
+
+{"description": "Valid numeric entity character U+00E1",
+"input": "&#x00e1;",
+"output": [["Character", "\u00E1"]]},
+
+{"description": "Valid numeric entity character U+00E2",
+"input": "&#x00e2;",
+"output": [["Character", "\u00E2"]]},
+
+{"description": "Valid numeric entity character U+00E3",
+"input": "&#x00e3;",
+"output": [["Character", "\u00E3"]]},
+
+{"description": "Valid numeric entity character U+00E4",
+"input": "&#x00e4;",
+"output": [["Character", "\u00E4"]]},
+
+{"description": "Valid numeric entity character U+00E5",
+"input": "&#x00e5;",
+"output": [["Character", "\u00E5"]]},
+
+{"description": "Valid numeric entity character U+00E6",
+"input": "&#x00e6;",
+"output": [["Character", "\u00E6"]]},
+
+{"description": "Valid numeric entity character U+00E7",
+"input": "&#x00e7;",
+"output": [["Character", "\u00E7"]]},
+
+{"description": "Valid numeric entity character U+00E8",
+"input": "&#x00e8;",
+"output": [["Character", "\u00E8"]]},
+
+{"description": "Valid numeric entity character U+00E9",
+"input": "&#x00e9;",
+"output": [["Character", "\u00E9"]]},
+
+{"description": "Valid numeric entity character U+00EA",
+"input": "&#x00ea;",
+"output": [["Character", "\u00EA"]]},
+
+{"description": "Valid numeric entity character U+00EB",
+"input": "&#x00eb;",
+"output": [["Character", "\u00EB"]]},
+
+{"description": "Valid numeric entity character U+00EC",
+"input": "&#x00ec;",
+"output": [["Character", "\u00EC"]]},
+
+{"description": "Valid numeric entity character U+00ED",
+"input": "&#x00ed;",
+"output": [["Character", "\u00ED"]]},
+
+{"description": "Valid numeric entity character U+00EE",
+"input": "&#x00ee;",
+"output": [["Character", "\u00EE"]]},
+
+{"description": "Valid numeric entity character U+00EF",
+"input": "&#x00ef;",
+"output": [["Character", "\u00EF"]]},
+
+{"description": "Valid numeric entity character U+00F0",
+"input": "&#x00f0;",
+"output": [["Character", "\u00F0"]]},
+
+{"description": "Valid numeric entity character U+00F1",
+"input": "&#x00f1;",
+"output": [["Character", "\u00F1"]]},
+
+{"description": "Valid numeric entity character U+00F2",
+"input": "&#x00f2;",
+"output": [["Character", "\u00F2"]]},
+
+{"description": "Valid numeric entity character U+00F3",
+"input": "&#x00f3;",
+"output": [["Character", "\u00F3"]]},
+
+{"description": "Valid numeric entity character U+00F4",
+"input": "&#x00f4;",
+"output": [["Character", "\u00F4"]]},
+
+{"description": "Valid numeric entity character U+00F5",
+"input": "&#x00f5;",
+"output": [["Character", "\u00F5"]]},
+
+{"description": "Valid numeric entity character U+00F6",
+"input": "&#x00f6;",
+"output": [["Character", "\u00F6"]]},
+
+{"description": "Valid numeric entity character U+00F7",
+"input": "&#x00f7;",
+"output": [["Character", "\u00F7"]]},
+
+{"description": "Valid numeric entity character U+00F8",
+"input": "&#x00f8;",
+"output": [["Character", "\u00F8"]]},
+
+{"description": "Valid numeric entity character U+00F9",
+"input": "&#x00f9;",
+"output": [["Character", "\u00F9"]]},
+
+{"description": "Valid numeric entity character U+00FA",
+"input": "&#x00fa;",
+"output": [["Character", "\u00FA"]]},
+
+{"description": "Valid numeric entity character U+00FB",
+"input": "&#x00fb;",
+"output": [["Character", "\u00FB"]]},
+
+{"description": "Valid numeric entity character U+00FC",
+"input": "&#x00fc;",
+"output": [["Character", "\u00FC"]]},
+
+{"description": "Valid numeric entity character U+00FD",
+"input": "&#x00fd;",
+"output": [["Character", "\u00FD"]]},
+
+{"description": "Valid numeric entity character U+00FE",
+"input": "&#x00fe;",
+"output": [["Character", "\u00FE"]]},
+
+{"description": "Valid numeric entity character U+00FF",
+"input": "&#x00ff;",
+"output": [["Character", "\u00FF"]]},
+
+{"description": "Valid numeric entity character U+D7FF",
+"input": "&#xd7ff;",
+"output": [["Character", "\uD7FF"]]},
+
+{"description": "Valid numeric entity character U+E000",
+"input": "&#xe000;",
+"output": [["Character", "\uE000"]]},
+
+{"description": "Valid numeric entity character U+FDCF",
+"input": "&#xfdcf;",
+"output": [["Character", "\uFDCF"]]},
+
+{"description": "Valid numeric entity character U+FDF0",
+"input": "&#xfdf0;",
+"output": [["Character", "\uFDF0"]]},
+
+{"description": "Valid numeric entity character U+FFFD",
+"input": "&#xfffd;",
+"output": [["Character", "\uFFFD"]]},
+
+{"description": "Valid numeric entity character U+10000",
+"input": "&#x10000;",
+"output": [["Character", "\uD800\uDC00"]]},
+
+{"description": "Valid numeric entity character U+1FFFD",
+"input": "&#x1fffd;",
+"output": [["Character", "\uD83F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+20000",
+"input": "&#x20000;",
+"output": [["Character", "\uD840\uDC00"]]},
+
+{"description": "Valid numeric entity character U+2FFFD",
+"input": "&#x2fffd;",
+"output": [["Character", "\uD87F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+30000",
+"input": "&#x30000;",
+"output": [["Character", "\uD880\uDC00"]]},
+
+{"description": "Valid numeric entity character U+3FFFD",
+"input": "&#x3fffd;",
+"output": [["Character", "\uD8BF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+40000",
+"input": "&#x40000;",
+"output": [["Character", "\uD8C0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+4FFFD",
+"input": "&#x4fffd;",
+"output": [["Character", "\uD8FF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+50000",
+"input": "&#x50000;",
+"output": [["Character", "\uD900\uDC00"]]},
+
+{"description": "Valid numeric entity character U+5FFFD",
+"input": "&#x5fffd;",
+"output": [["Character", "\uD93F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+60000",
+"input": "&#x60000;",
+"output": [["Character", "\uD940\uDC00"]]},
+
+{"description": "Valid numeric entity character U+6FFFD",
+"input": "&#x6fffd;",
+"output": [["Character", "\uD97F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+70000",
+"input": "&#x70000;",
+"output": [["Character", "\uD980\uDC00"]]},
+
+{"description": "Valid numeric entity character U+7FFFD",
+"input": "&#x7fffd;",
+"output": [["Character", "\uD9BF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+80000",
+"input": "&#x80000;",
+"output": [["Character", "\uD9C0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+8FFFD",
+"input": "&#x8fffd;",
+"output": [["Character", "\uD9FF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+90000",
+"input": "&#x90000;",
+"output": [["Character", "\uDA00\uDC00"]]},
+
+{"description": "Valid numeric entity character U+9FFFD",
+"input": "&#x9fffd;",
+"output": [["Character", "\uDA3F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+A0000",
+"input": "&#xa0000;",
+"output": [["Character", "\uDA40\uDC00"]]},
+
+{"description": "Valid numeric entity character U+AFFFD",
+"input": "&#xafffd;",
+"output": [["Character", "\uDA7F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+B0000",
+"input": "&#xb0000;",
+"output": [["Character", "\uDA80\uDC00"]]},
+
+{"description": "Valid numeric entity character U+BFFFD",
+"input": "&#xbfffd;",
+"output": [["Character", "\uDABF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+C0000",
+"input": "&#xc0000;",
+"output": [["Character", "\uDAC0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+CFFFD",
+"input": "&#xcfffd;",
+"output": [["Character", "\uDAFF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+D0000",
+"input": "&#xd0000;",
+"output": [["Character", "\uDB00\uDC00"]]},
+
+{"description": "Valid numeric entity character U+DFFFD",
+"input": "&#xdfffd;",
+"output": [["Character", "\uDB3F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+E0000",
+"input": "&#xe0000;",
+"output": [["Character", "\uDB40\uDC00"]]},
+
+{"description": "Valid numeric entity character U+EFFFD",
+"input": "&#xefffd;",
+"output": [["Character", "\uDB7F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+F0000",
+"input": "&#xf0000;",
+"output": [["Character", "\uDB80\uDC00"]]},
+
+{"description": "Valid numeric entity character U+FFFFD",
+"input": "&#xffffd;",
+"output": [["Character", "\uDBBF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+100000",
+"input": "&#x100000;",
+"output": [["Character", "\uDBC0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+10FFFD",
+"input": "&#x10fffd;",
+"output": [["Character", "\uDBFF\uDFFD"]]}
+
+]}
+
+
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/pendingSpecChanges.test b/pkg/third_party/html5lib/test/data/tokenizer/pendingSpecChanges.test
new file mode 100644
index 0000000..1b7dc3c
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/pendingSpecChanges.test
@@ -0,0 +1,7 @@
+{"tests": [
+
+{"description":"<!---- >",
+"input":"<!---- >",
+"output":["ParseError", "ParseError", ["Comment","-- >"]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/test1.test b/pkg/third_party/html5lib/test/data/tokenizer/test1.test
new file mode 100644
index 0000000..5de66f5
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/test1.test
@@ -0,0 +1,196 @@
+{"tests": [
+
+{"description":"Correct Doctype lowercase",
+"input":"<!DOCTYPE html>",
+"output":[["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Correct Doctype uppercase",
+"input":"<!DOCTYPE HTML>",
+"output":[["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Correct Doctype mixed case",
+"input":"<!DOCTYPE HtMl>", 
+"output":[["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Correct Doctype case with EOF",
+"input":"<!DOCTYPE HtMl", 
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Truncated doctype start",
+"input":"<!DOC>", 
+"output":["ParseError", ["Comment", "DOC"]]},
+
+{"description":"Doctype in error",
+"input":"<!DOCTYPE foo>", 
+"output":[["DOCTYPE", "foo", null, null, true]]},
+
+{"description":"Single Start Tag",
+"input":"<h>",
+"output":[["StartTag", "h", {}]]},
+
+{"description":"Empty end tag",
+"input":"</>",
+"output":["ParseError"]},
+
+{"description":"Empty start tag",
+"input":"<>",
+"output":["ParseError", ["Character", "<>"]]},
+
+{"description":"Start Tag w/attribute",
+"input":"<h a='b'>",
+"output":[["StartTag", "h", {"a":"b"}]]},
+
+{"description":"Start Tag w/attribute no quotes",
+"input":"<h a=b>",
+"output":[["StartTag", "h", {"a":"b"}]]},
+
+{"description":"Start/End Tag",
+"input":"<h></h>",
+"output":[["StartTag", "h", {}], ["EndTag", "h"]]},
+
+{"description":"Two unclosed start tags",
+"input":"<p>One<p>Two",
+"output":[["StartTag", "p", {}], ["Character", "One"], ["StartTag", "p", {}], ["Character", "Two"]]},
+
+{"description":"End Tag w/attribute",
+"input":"<h></h a='b'>",
+"output":[["StartTag", "h", {}], "ParseError", ["EndTag", "h"]]},
+
+{"description":"Multiple atts",
+"input":"<h a='b' c='d'>",
+"output":[["StartTag", "h", {"a":"b", "c":"d"}]]},
+
+{"description":"Multiple atts no space",
+"input":"<h a='b'c='d'>",
+"output":["ParseError", ["StartTag", "h", {"a":"b", "c":"d"}]]},
+
+{"description":"Repeated attr",
+ "input":"<h a='b' a='d'>",
+ "output":["ParseError", ["StartTag", "h", {"a":"b"}]]},
+
+{"description":"Simple comment",
+ "input":"<!--comment-->",
+ "output":[["Comment", "comment"]]},
+
+{"description":"Comment, Central dash no space",
+ "input":"<!----->",
+ "output":["ParseError", ["Comment", "-"]]},
+
+{"description":"Comment, two central dashes",
+"input":"<!-- --comment -->",
+"output":["ParseError", ["Comment", " --comment "]]},
+
+{"description":"Unfinished comment",
+"input":"<!--comment",
+"output":["ParseError", ["Comment", "comment"]]},
+
+{"description":"Start of a comment",
+"input":"<!-",
+"output":["ParseError", ["Comment", "-"]]},
+
+{"description":"Short comment",
+ "input":"<!-->",
+ "output":["ParseError", ["Comment", ""]]},
+
+{"description":"Short comment two",
+ "input":"<!--->",
+ "output":["ParseError", ["Comment", ""]]},
+
+{"description":"Short comment three",
+ "input":"<!---->",
+ "output":[["Comment", ""]]},
+
+
+{"description":"Ampersand EOF",
+"input":"&",
+"output":[["Character", "&"]]},
+
+{"description":"Ampersand ampersand EOF",
+"input":"&&",
+"output":[["Character", "&&"]]},
+
+{"description":"Ampersand space EOF",
+"input":"& ",
+"output":[["Character", "& "]]},
+
+{"description":"Unfinished entity",
+"input":"&f",
+"output":["ParseError", ["Character", "&f"]]},
+
+{"description":"Ampersand, number sign",
+"input":"&#",
+"output":["ParseError", ["Character", "&#"]]},
+
+{"description":"Unfinished numeric entity",
+"input":"&#x",
+"output":["ParseError", ["Character", "&#x"]]},
+
+{"description":"Entity with trailing semicolon (1)",
+"input":"I'm &not;it",
+"output":[["Character","I'm \u00ACit"]]},
+
+{"description":"Entity with trailing semicolon (2)",
+"input":"I'm &notin;",
+"output":[["Character","I'm \u2209"]]},
+
+{"description":"Entity without trailing semicolon (1)",
+"input":"I'm &notit",
+"output":[["Character","I'm "], "ParseError", ["Character", "\u00ACit"]]},
+
+{"description":"Entity without trailing semicolon (2)",
+"input":"I'm &notin",
+"output":[["Character","I'm "], "ParseError", ["Character", "\u00ACin"]]},
+
+{"description":"Partial entity match at end of file",
+"input":"I'm &no",
+"output":[["Character","I'm "], "ParseError", ["Character", "&no"]]},
+
+{"description":"Non-ASCII character reference name",
+"input":"&\u00AC;",
+"output":["ParseError", ["Character", "&\u00AC;"]]},
+
+{"description":"ASCII decimal entity",
+"input":"&#0036;",
+"output":[["Character","$"]]},
+
+{"description":"ASCII hexadecimal entity",
+"input":"&#x3f;",
+"output":[["Character","?"]]},
+
+{"description":"Hexadecimal entity in attribute",
+"input":"<h a='&#x3f;'></h>",
+"output":[["StartTag", "h", {"a":"?"}], ["EndTag", "h"]]},
+
+{"description":"Entity in attribute without semicolon ending in x",
+"input":"<h a='&notx'>",
+"output":["ParseError", ["StartTag", "h", {"a":"&notx"}]]},
+
+{"description":"Entity in attribute without semicolon ending in 1",
+"input":"<h a='&not1'>",
+"output":["ParseError", ["StartTag", "h", {"a":"&not1"}]]},
+
+{"description":"Entity in attribute without semicolon ending in i",
+"input":"<h a='&noti'>",
+"output":["ParseError", ["StartTag", "h", {"a":"&noti"}]]},
+
+{"description":"Entity in attribute without semicolon",
+"input":"<h a='&COPY'>",
+"output":["ParseError", ["StartTag", "h", {"a":"\u00A9"}]]},
+
+{"description":"Unquoted attribute ending in ampersand",
+"input":"<s o=& t>",
+"output":[["StartTag","s",{"o":"&","t":""}]]},
+
+{"description":"Unquoted attribute at end of tag with final character of &, with tag followed by characters",
+"input":"<a a=a&>foo",
+"output":[["StartTag", "a", {"a":"a&"}], ["Character", "foo"]]},
+
+{"description":"plaintext element",
+ "input":"<plaintext>foobar",
+ "output":[["StartTag","plaintext",{}], ["Character","foobar"]]},
+
+{"description":"Open angled bracket in unquoted attribute value state",
+ "input":"<a a=f<>",
+ "output":["ParseError", ["StartTag", "a", {"a":"f<"}]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/test2.test b/pkg/third_party/html5lib/test/data/tokenizer/test2.test
new file mode 100644
index 0000000..e157514
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/test2.test
@@ -0,0 +1,179 @@
+{"tests": [
+
+{"description":"DOCTYPE without name",
+"input":"<!DOCTYPE>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"DOCTYPE without space before name",
+"input":"<!DOCTYPEhtml>",
+"output":["ParseError", ["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Incorrect DOCTYPE without a space before name",
+"input":"<!DOCTYPEfoo>",
+"output":["ParseError", ["DOCTYPE", "foo", null, null, true]]},
+
+{"description":"DOCTYPE with publicId",
+"input":"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML Transitional 4.01//EN\">",
+"output":[["DOCTYPE", "html", "-//W3C//DTD HTML Transitional 4.01//EN", null, true]]},
+
+{"description":"DOCTYPE with EOF after PUBLIC",
+"input":"<!DOCTYPE html PUBLIC",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"DOCTYPE with EOF after PUBLIC '",
+"input":"<!DOCTYPE html PUBLIC '",
+"output":["ParseError", ["DOCTYPE", "html", "", null, false]]},
+
+{"description":"DOCTYPE with EOF after PUBLIC 'x",
+"input":"<!DOCTYPE html PUBLIC 'x",
+"output":["ParseError", ["DOCTYPE", "html", "x", null, false]]},
+
+{"description":"DOCTYPE with systemId",
+"input":"<!DOCTYPE html SYSTEM \"-//W3C//DTD HTML Transitional 4.01//EN\">",
+"output":[["DOCTYPE", "html", null, "-//W3C//DTD HTML Transitional 4.01//EN", true]]},
+
+{"description":"DOCTYPE with publicId and systemId",
+"input":"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML Transitional 4.01//EN\" \"-//W3C//DTD HTML Transitional 4.01//EN\">",
+"output":[["DOCTYPE", "html", "-//W3C//DTD HTML Transitional 4.01//EN", "-//W3C//DTD HTML Transitional 4.01//EN", true]]},
+
+{"description":"DOCTYPE with > in double-quoted publicId",
+"input":"<!DOCTYPE html PUBLIC \">x",
+"output":["ParseError", ["DOCTYPE", "html", "", null, false], ["Character", "x"]]},
+
+{"description":"DOCTYPE with > in single-quoted publicId",
+"input":"<!DOCTYPE html PUBLIC '>x",
+"output":["ParseError", ["DOCTYPE", "html", "", null, false], ["Character", "x"]]},
+
+{"description":"DOCTYPE with > in double-quoted systemId",
+"input":"<!DOCTYPE html PUBLIC \"foo\" \">x",
+"output":["ParseError", ["DOCTYPE", "html", "foo", "", false], ["Character", "x"]]},
+
+{"description":"DOCTYPE with > in single-quoted systemId",
+"input":"<!DOCTYPE html PUBLIC 'foo' '>x",
+"output":["ParseError", ["DOCTYPE", "html", "foo", "", false], ["Character", "x"]]},
+
+{"description":"Incomplete doctype",
+"input":"<!DOCTYPE html ",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Numeric entity representing the NUL character",
+"input":"&#0000;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity representing the NUL character",
+"input":"&#x0000;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Numeric entity representing a codepoint after 1114111 (U+10FFFF)",
+"input":"&#2225222;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity representing a codepoint after 1114111 (U+10FFFF)",
+"input":"&#x1010FFFF;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity pair representing a surrogate pair",
+"input":"&#xD869;&#xDED6;",
+"output":["ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity with mixed uppercase and lowercase",
+"input":"&#xaBcD;",
+"output":[["Character", "\uABCD"]]},
+
+{"description":"Entity without a name",
+"input":"&;",
+"output":["ParseError", ["Character", "&;"]]},
+
+{"description":"Unescaped ampersand in attribute value",
+"input":"<h a='&'>",
+"output":[["StartTag", "h", { "a":"&" }]]},
+
+{"description":"StartTag containing <",
+"input":"<a<b>",
+"output":[["StartTag", "a<b", { }]]},
+
+{"description":"Non-void element containing trailing /",
+"input":"<h/>",
+"output":[["StartTag","h",{},true]]},
+
+{"description":"Void element with permitted slash",
+"input":"<br/>",
+"output":[["StartTag","br",{},true]]},
+
+{"description":"Void element with permitted slash (with attribute)",
+"input":"<br foo='bar'/>",
+"output":[["StartTag","br",{"foo":"bar"},true]]},
+
+{"description":"StartTag containing /",
+"input":"<h/a='b'>",
+"output":["ParseError", ["StartTag", "h", { "a":"b" }]]},
+
+{"description":"Double-quoted attribute value",
+"input":"<h a=\"b\">",
+"output":[["StartTag", "h", { "a":"b" }]]},
+
+{"description":"Unescaped </",
+"input":"</",
+"output":["ParseError", ["Character", "</"]]},
+
+{"description":"Illegal end tag name",
+"input":"</1>",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"Simili processing instruction",
+"input":"<?namespace>",
+"output":["ParseError", ["Comment", "?namespace"]]},
+
+{"description":"A bogus comment stops at >, even if preceeded by two dashes",
+"input":"<?foo-->",
+"output":["ParseError", ["Comment", "?foo--"]]},
+
+{"description":"Unescaped <",
+"input":"foo < bar",
+"output":[["Character", "foo "], "ParseError", ["Character", "< bar"]]},
+
+{"description":"Null Byte Replacement",
+"input":"\u0000",
+"output":["ParseError", ["Character", "\u0000"]]},
+
+{"description":"Comment with dash",
+"input":"<!---x",
+"output":["ParseError", ["Comment", "-x"]]},
+
+{"description":"Entity + newline",
+"input":"\nx\n&gt;\n",
+"output":[["Character","\nx\n>\n"]]},
+
+{"description":"Start tag with no attributes but space before the greater-than sign",
+"input":"<h >",
+"output":[["StartTag", "h", {}]]},
+
+{"description":"Empty attribute followed by uppercase attribute",
+"input":"<h a B=''>",
+"output":[["StartTag", "h", {"a":"", "b":""}]]},
+
+{"description":"Double-quote after attribute name",
+"input":"<h a \">",
+"output":["ParseError", ["StartTag", "h", {"a":"", "\"":""}]]},
+
+{"description":"Single-quote after attribute name",
+"input":"<h a '>",
+"output":["ParseError", ["StartTag", "h", {"a":"", "'":""}]]},
+
+{"description":"Empty end tag with following characters",
+"input":"a</>bc",
+"output":[["Character", "a"], "ParseError", ["Character", "bc"]]},
+
+{"description":"Empty end tag with following tag",
+"input":"a</><b>c",
+"output":[["Character", "a"], "ParseError", ["StartTag", "b", {}], ["Character", "c"]]},
+
+{"description":"Empty end tag with following comment",
+"input":"a</><!--b-->c",
+"output":[["Character", "a"], "ParseError", ["Comment", "b"], ["Character", "c"]]},
+
+{"description":"Empty end tag with following end tag",
+"input":"a</></b>c",
+"output":[["Character", "a"], "ParseError", ["EndTag", "b"], ["Character", "c"]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/test3.test b/pkg/third_party/html5lib/test/data/tokenizer/test3.test
new file mode 100644
index 0000000..58519e8
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/test3.test
@@ -0,0 +1,6047 @@
+{"tests": [
+
+{"description":"",
+"input":"",
+"output":[]},
+
+{"description":"\\u0009",
+"input":"\u0009",
+"output":[["Character", "\u0009"]]},
+
+{"description":"\\u000A",
+"input":"\u000A",
+"output":[["Character", "\u000A"]]},
+
+{"description":"\\u000B",
+"input":"\u000B",
+"output":["ParseError", ["Character", "\u000B"]]},
+
+{"description":"\\u000C",
+"input":"\u000C",
+"output":[["Character", "\u000C"]]},
+
+{"description":" ",
+"input":" ",
+"output":[["Character", " "]]},
+
+{"description":"!",
+"input":"!",
+"output":[["Character", "!"]]},
+
+{"description":"\"",
+"input":"\"",
+"output":[["Character", "\""]]},
+
+{"description":"%",
+"input":"%",
+"output":[["Character", "%"]]},
+
+{"description":"&",
+"input":"&",
+"output":[["Character", "&"]]},
+
+{"description":"'",
+"input":"'",
+"output":[["Character", "'"]]},
+
+{"description":",",
+"input":",",
+"output":[["Character", ","]]},
+
+{"description":"-",
+"input":"-",
+"output":[["Character", "-"]]},
+
+{"description":".",
+"input":".",
+"output":[["Character", "."]]},
+
+{"description":"/",
+"input":"/",
+"output":[["Character", "/"]]},
+
+{"description":"0",
+"input":"0",
+"output":[["Character", "0"]]},
+
+{"description":"1",
+"input":"1",
+"output":[["Character", "1"]]},
+
+{"description":"9",
+"input":"9",
+"output":[["Character", "9"]]},
+
+{"description":";",
+"input":";",
+"output":[["Character", ";"]]},
+
+{"description":"<",
+"input":"<",
+"output":["ParseError", ["Character", "<"]]},
+
+{"description":"<\\u0000",
+"input":"<\u0000",
+"output":["ParseError", ["Character", "<"], "ParseError", ["Character", "\u0000"]]},
+
+{"description":"<\\u0009",
+"input":"<\u0009",
+"output":["ParseError", ["Character", "<\u0009"]]},
+
+{"description":"<\\u000A",
+"input":"<\u000A",
+"output":["ParseError", ["Character", "<\u000A"]]},
+
+{"description":"<\\u000B",
+"input":"<\u000B",
+"output":["ParseError", "ParseError", ["Character", "<\u000B"]]},
+
+{"description":"<\\u000C",
+"input":"<\u000C",
+"output":["ParseError", ["Character", "<\u000C"]]},
+
+{"description":"< ",
+"input":"< ",
+"output":["ParseError", ["Character", "< "]]},
+
+{"description":"<!",
+"input":"<!",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!\\u0000",
+"input":"<!\u0000",
+"output":["ParseError", ["Comment", "\uFFFD"]]},
+
+{"description":"<!\\u0009",
+"input":"<!\u0009",
+"output":["ParseError", ["Comment", "\u0009"]]},
+
+{"description":"<!\\u000A",
+"input":"<!\u000A",
+"output":["ParseError", ["Comment", "\u000A"]]},
+
+{"description":"<!\\u000B",
+"input":"<!\u000B",
+"output":["ParseError", "ParseError", ["Comment", "\u000B"]]},
+
+{"description":"<!\\u000C",
+"input":"<!\u000C",
+"output":["ParseError", ["Comment", "\u000C"]]},
+
+{"description":"<! ",
+"input":"<! ",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!!",
+"input":"<!!",
+"output":["ParseError", ["Comment", "!"]]},
+
+{"description":"<!\"",
+"input":"<!\"",
+"output":["ParseError", ["Comment", "\""]]},
+
+{"description":"<!&",
+"input":"<!&",
+"output":["ParseError", ["Comment", "&"]]},
+
+{"description":"<!'",
+"input":"<!'",
+"output":["ParseError", ["Comment", "'"]]},
+
+{"description":"<!-",
+"input":"<!-",
+"output":["ParseError", ["Comment", "-"]]},
+
+{"description":"<!--",
+"input":"<!--",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!--\\u0000",
+"input":"<!--\u0000",
+"output":["ParseError", "ParseError", ["Comment", "\uFFFD"]]},
+
+{"description":"<!--\\u0009",
+"input":"<!--\u0009",
+"output":["ParseError", ["Comment", "\u0009"]]},
+
+{"description":"<!--\\u000A",
+"input":"<!--\u000A",
+"output":["ParseError", ["Comment", "\u000A"]]},
+
+{"description":"<!--\\u000B",
+"input":"<!--\u000B",
+"output":["ParseError", "ParseError", ["Comment", "\u000B"]]},
+
+{"description":"<!--\\u000C",
+"input":"<!--\u000C",
+"output":["ParseError", ["Comment", "\u000C"]]},
+
+{"description":"<!-- ",
+"input":"<!-- ",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!-- \\u0000",
+"input":"<!-- \u0000",
+"output":["ParseError", "ParseError", ["Comment", " \uFFFD"]]},
+
+{"description":"<!-- \\u0009",
+"input":"<!-- \u0009",
+"output":["ParseError", ["Comment", " \u0009"]]},
+
+{"description":"<!-- \\u000A",
+"input":"<!-- \u000A",
+"output":["ParseError", ["Comment", " \u000A"]]},
+
+{"description":"<!-- \\u000B",
+"input":"<!-- \u000B",
+"output":["ParseError", "ParseError", ["Comment", " \u000B"]]},
+
+{"description":"<!-- \\u000C",
+"input":"<!-- \u000C",
+"output":["ParseError", ["Comment", " \u000C"]]},
+
+{"description":"<!--  ",
+"input":"<!--  ",
+"output":["ParseError", ["Comment", "  "]]},
+
+{"description":"<!-- !",
+"input":"<!-- !",
+"output":["ParseError", ["Comment", " !"]]},
+
+{"description":"<!-- \"",
+"input":"<!-- \"",
+"output":["ParseError", ["Comment", " \""]]},
+
+{"description":"<!-- &",
+"input":"<!-- &",
+"output":["ParseError", ["Comment", " &"]]},
+
+{"description":"<!-- '",
+"input":"<!-- '",
+"output":["ParseError", ["Comment", " '"]]},
+
+{"description":"<!-- ,",
+"input":"<!-- ,",
+"output":["ParseError", ["Comment", " ,"]]},
+
+{"description":"<!-- -",
+"input":"<!-- -",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!-- -\\u0000",
+"input":"<!-- -\u0000",
+"output":["ParseError", "ParseError", ["Comment", " -\uFFFD"]]},
+
+{"description":"<!-- -\\u0009",
+"input":"<!-- -\u0009",
+"output":["ParseError", ["Comment", " -\u0009"]]},
+
+{"description":"<!-- -\\u000A",
+"input":"<!-- -\u000A",
+"output":["ParseError", ["Comment", " -\u000A"]]},
+
+{"description":"<!-- -\\u000B",
+"input":"<!-- -\u000B",
+"output":["ParseError", "ParseError", ["Comment", " -\u000B"]]},
+
+{"description":"<!-- -\\u000C",
+"input":"<!-- -\u000C",
+"output":["ParseError", ["Comment", " -\u000C"]]},
+
+{"description":"<!-- - ",
+"input":"<!-- - ",
+"output":["ParseError", ["Comment", " - "]]},
+
+{"description":"<!-- -!",
+"input":"<!-- -!",
+"output":["ParseError", ["Comment", " -!"]]},
+
+{"description":"<!-- -\"",
+"input":"<!-- -\"",
+"output":["ParseError", ["Comment", " -\""]]},
+
+{"description":"<!-- -&",
+"input":"<!-- -&",
+"output":["ParseError", ["Comment", " -&"]]},
+
+{"description":"<!-- -'",
+"input":"<!-- -'",
+"output":["ParseError", ["Comment", " -'"]]},
+
+{"description":"<!-- -,",
+"input":"<!-- -,",
+"output":["ParseError", ["Comment", " -,"]]},
+
+{"description":"<!-- --",
+"input":"<!-- --",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!-- -.",
+"input":"<!-- -.",
+"output":["ParseError", ["Comment", " -."]]},
+
+{"description":"<!-- -/",
+"input":"<!-- -/",
+"output":["ParseError", ["Comment", " -/"]]},
+
+{"description":"<!-- -0",
+"input":"<!-- -0",
+"output":["ParseError", ["Comment", " -0"]]},
+
+{"description":"<!-- -1",
+"input":"<!-- -1",
+"output":["ParseError", ["Comment", " -1"]]},
+
+{"description":"<!-- -9",
+"input":"<!-- -9",
+"output":["ParseError", ["Comment", " -9"]]},
+
+{"description":"<!-- -<",
+"input":"<!-- -<",
+"output":["ParseError", ["Comment", " -<"]]},
+
+{"description":"<!-- -=",
+"input":"<!-- -=",
+"output":["ParseError", ["Comment", " -="]]},
+
+{"description":"<!-- ->",
+"input":"<!-- ->",
+"output":["ParseError", ["Comment", " ->"]]},
+
+{"description":"<!-- -?",
+"input":"<!-- -?",
+"output":["ParseError", ["Comment", " -?"]]},
+
+{"description":"<!-- -@",
+"input":"<!-- -@",
+"output":["ParseError", ["Comment", " -@"]]},
+
+{"description":"<!-- -A",
+"input":"<!-- -A",
+"output":["ParseError", ["Comment", " -A"]]},
+
+{"description":"<!-- -B",
+"input":"<!-- -B",
+"output":["ParseError", ["Comment", " -B"]]},
+
+{"description":"<!-- -Y",
+"input":"<!-- -Y",
+"output":["ParseError", ["Comment", " -Y"]]},
+
+{"description":"<!-- -Z",
+"input":"<!-- -Z",
+"output":["ParseError", ["Comment", " -Z"]]},
+
+{"description":"<!-- -`",
+"input":"<!-- -`",
+"output":["ParseError", ["Comment", " -`"]]},
+
+{"description":"<!-- -a",
+"input":"<!-- -a",
+"output":["ParseError", ["Comment", " -a"]]},
+
+{"description":"<!-- -b",
+"input":"<!-- -b",
+"output":["ParseError", ["Comment", " -b"]]},
+
+{"description":"<!-- -y",
+"input":"<!-- -y",
+"output":["ParseError", ["Comment", " -y"]]},
+
+{"description":"<!-- -z",
+"input":"<!-- -z",
+"output":["ParseError", ["Comment", " -z"]]},
+
+{"description":"<!-- -{",
+"input":"<!-- -{",
+"output":["ParseError", ["Comment", " -{"]]},
+
+{"description":"<!-- -\\uDBC0\\uDC00",
+"input":"<!-- -\uDBC0\uDC00",
+"output":["ParseError", ["Comment", " -\uDBC0\uDC00"]]},
+
+{"description":"<!-- .",
+"input":"<!-- .",
+"output":["ParseError", ["Comment", " ."]]},
+
+{"description":"<!-- /",
+"input":"<!-- /",
+"output":["ParseError", ["Comment", " /"]]},
+
+{"description":"<!-- 0",
+"input":"<!-- 0",
+"output":["ParseError", ["Comment", " 0"]]},
+
+{"description":"<!-- 1",
+"input":"<!-- 1",
+"output":["ParseError", ["Comment", " 1"]]},
+
+{"description":"<!-- 9",
+"input":"<!-- 9",
+"output":["ParseError", ["Comment", " 9"]]},
+
+{"description":"<!-- <",
+"input":"<!-- <",
+"output":["ParseError", ["Comment", " <"]]},
+
+{"description":"<!-- =",
+"input":"<!-- =",
+"output":["ParseError", ["Comment", " ="]]},
+
+{"description":"<!-- >",
+"input":"<!-- >",
+"output":["ParseError", ["Comment", " >"]]},
+
+{"description":"<!-- ?",
+"input":"<!-- ?",
+"output":["ParseError", ["Comment", " ?"]]},
+
+{"description":"<!-- @",
+"input":"<!-- @",
+"output":["ParseError", ["Comment", " @"]]},
+
+{"description":"<!-- A",
+"input":"<!-- A",
+"output":["ParseError", ["Comment", " A"]]},
+
+{"description":"<!-- B",
+"input":"<!-- B",
+"output":["ParseError", ["Comment", " B"]]},
+
+{"description":"<!-- Y",
+"input":"<!-- Y",
+"output":["ParseError", ["Comment", " Y"]]},
+
+{"description":"<!-- Z",
+"input":"<!-- Z",
+"output":["ParseError", ["Comment", " Z"]]},
+
+{"description":"<!-- `",
+"input":"<!-- `",
+"output":["ParseError", ["Comment", " `"]]},
+
+{"description":"<!-- a",
+"input":"<!-- a",
+"output":["ParseError", ["Comment", " a"]]},
+
+{"description":"<!-- b",
+"input":"<!-- b",
+"output":["ParseError", ["Comment", " b"]]},
+
+{"description":"<!-- y",
+"input":"<!-- y",
+"output":["ParseError", ["Comment", " y"]]},
+
+{"description":"<!-- z",
+"input":"<!-- z",
+"output":["ParseError", ["Comment", " z"]]},
+
+{"description":"<!-- {",
+"input":"<!-- {",
+"output":["ParseError", ["Comment", " {"]]},
+
+{"description":"<!-- \\uDBC0\\uDC00",
+"input":"<!-- \uDBC0\uDC00",
+"output":["ParseError", ["Comment", " \uDBC0\uDC00"]]},
+
+{"description":"<!--!",
+"input":"<!--!",
+"output":["ParseError", ["Comment", "!"]]},
+
+{"description":"<!--\"",
+"input":"<!--\"",
+"output":["ParseError", ["Comment", "\""]]},
+
+{"description":"<!--&",
+"input":"<!--&",
+"output":["ParseError", ["Comment", "&"]]},
+
+{"description":"<!--'",
+"input":"<!--'",
+"output":["ParseError", ["Comment", "'"]]},
+
+{"description":"<!--,",
+"input":"<!--,",
+"output":["ParseError", ["Comment", ","]]},
+
+{"description":"<!---",
+"input":"<!---",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!---\\u0000",
+"input":"<!---\u0000",
+"output":["ParseError", "ParseError", ["Comment", "-\uFFFD"]]},
+
+{"description":"<!---\\u0009",
+"input":"<!---\u0009",
+"output":["ParseError", ["Comment", "-\u0009"]]},
+
+{"description":"<!---\\u000A",
+"input":"<!---\u000A",
+"output":["ParseError", ["Comment", "-\u000A"]]},
+
+{"description":"<!---\\u000B",
+"input":"<!---\u000B",
+"output":["ParseError", "ParseError", ["Comment", "-\u000B"]]},
+
+{"description":"<!---\\u000C",
+"input":"<!---\u000C",
+"output":["ParseError", ["Comment", "-\u000C"]]},
+
+{"description":"<!--- ",
+"input":"<!--- ",
+"output":["ParseError", ["Comment", "- "]]},
+
+{"description":"<!---!",
+"input":"<!---!",
+"output":["ParseError", ["Comment", "-!"]]},
+
+{"description":"<!---\"",
+"input":"<!---\"",
+"output":["ParseError", ["Comment", "-\""]]},
+
+{"description":"<!---&",
+"input":"<!---&",
+"output":["ParseError", ["Comment", "-&"]]},
+
+{"description":"<!---'",
+"input":"<!---'",
+"output":["ParseError", ["Comment", "-'"]]},
+
+{"description":"<!---,",
+"input":"<!---,",
+"output":["ParseError", ["Comment", "-,"]]},
+
+{"description":"<!----",
+"input":"<!----",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!----\\u0000",
+"input":"<!----\u0000",
+"output":["ParseError", "ParseError", ["Comment", "--\uFFFD"]]},
+
+{"description":"<!----\\u0009",
+"input":"<!----\u0009",
+"output":["ParseError", "ParseError", ["Comment", "--\u0009"]]},
+
+{"description":"<!----\\u000A",
+"input":"<!----\u000A",
+"output":["ParseError", "ParseError", ["Comment", "--\u000A"]]},
+
+{"description":"<!----\\u000B",
+"input":"<!----\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["Comment", "--\u000B"]]},
+
+{"description":"<!----\\u000C",
+"input":"<!----\u000C",
+"output":["ParseError", "ParseError", ["Comment", "--\u000C"]]},
+
+{"description":"<!---- ",
+"input":"<!---- ",
+"output":["ParseError", "ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- -",
+"input":"<!---- -",
+"output":["ParseError", "ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- --",
+"input":"<!---- --",
+"output":["ParseError", "ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- -->",
+"input":"<!---- -->",
+"output":["ParseError", ["Comment", "-- "]]},
+
+{"description":"<!----  -->",
+"input":"<!----  -->",
+"output":["ParseError", ["Comment", "--  "]]},
+
+{"description":"<!---- a-->",
+"input":"<!---- a-->",
+"output":["ParseError", ["Comment", "-- a"]]},
+
+{"description":"<!----!",
+"input":"<!----!",
+"output":["ParseError", "ParseError", ["Comment", ""]]},
+
+{"description":"<!----!>",
+"input":"<!----!>",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!----!a",
+"input":"<!----!a",
+"output":["ParseError", "ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!a-",
+"input":"<!----!a-",
+"output":["ParseError", "ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!a--",
+"input":"<!----!a--",
+"output":["ParseError", "ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!a-->",
+"input":"<!----!a-->",
+"output":["ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!-",
+"input":"<!----!-",
+"output":["ParseError", "ParseError", ["Comment", "--!"]]},
+
+{"description":"<!----!--",
+"input":"<!----!--",
+"output":["ParseError", "ParseError", ["Comment", "--!"]]},
+
+{"description":"<!----!-->",
+"input":"<!----!-->",
+"output":["ParseError", ["Comment", "--!"]]},
+
+{"description":"<!----\"",
+"input":"<!----\"",
+"output":["ParseError", "ParseError", ["Comment", "--\""]]},
+
+{"description":"<!----&",
+"input":"<!----&",
+"output":["ParseError", "ParseError", ["Comment", "--&"]]},
+
+{"description":"<!----'",
+"input":"<!----'",
+"output":["ParseError", "ParseError", ["Comment", "--'"]]},
+
+{"description":"<!----,",
+"input":"<!----,",
+"output":["ParseError", "ParseError", ["Comment", "--,"]]},
+
+{"description":"<!-----",
+"input":"<!-----",
+"output":["ParseError", "ParseError", ["Comment", "-"]]},
+
+{"description":"<!----.",
+"input":"<!----.",
+"output":["ParseError", "ParseError", ["Comment", "--."]]},
+
+{"description":"<!----/",
+"input":"<!----/",
+"output":["ParseError", "ParseError", ["Comment", "--/"]]},
+
+{"description":"<!----0",
+"input":"<!----0",
+"output":["ParseError", "ParseError", ["Comment", "--0"]]},
+
+{"description":"<!----1",
+"input":"<!----1",
+"output":["ParseError", "ParseError", ["Comment", "--1"]]},
+
+{"description":"<!----9",
+"input":"<!----9",
+"output":["ParseError", "ParseError", ["Comment", "--9"]]},
+
+{"description":"<!----<",
+"input":"<!----<",
+"output":["ParseError", "ParseError", ["Comment", "--<"]]},
+
+{"description":"<!----=",
+"input":"<!----=",
+"output":["ParseError", "ParseError", ["Comment", "--="]]},
+
+{"description":"<!---->",
+"input":"<!---->",
+"output":[["Comment", ""]]},
+
+{"description":"<!----?",
+"input":"<!----?",
+"output":["ParseError", "ParseError", ["Comment", "--?"]]},
+
+{"description":"<!----@",
+"input":"<!----@",
+"output":["ParseError", "ParseError", ["Comment", "--@"]]},
+
+{"description":"<!----A",
+"input":"<!----A",
+"output":["ParseError", "ParseError", ["Comment", "--A"]]},
+
+{"description":"<!----B",
+"input":"<!----B",
+"output":["ParseError", "ParseError", ["Comment", "--B"]]},
+
+{"description":"<!----Y",
+"input":"<!----Y",
+"output":["ParseError", "ParseError", ["Comment", "--Y"]]},
+
+{"description":"<!----Z",
+"input":"<!----Z",
+"output":["ParseError", "ParseError", ["Comment", "--Z"]]},
+
+{"description":"<!----`",
+"input":"<!----`",
+"output":["ParseError", "ParseError", ["Comment", "--`"]]},
+
+{"description":"<!----a",
+"input":"<!----a",
+"output":["ParseError", "ParseError", ["Comment", "--a"]]},
+
+{"description":"<!----b",
+"input":"<!----b",
+"output":["ParseError", "ParseError", ["Comment", "--b"]]},
+
+{"description":"<!----y",
+"input":"<!----y",
+"output":["ParseError", "ParseError", ["Comment", "--y"]]},
+
+{"description":"<!----z",
+"input":"<!----z",
+"output":["ParseError", "ParseError", ["Comment", "--z"]]},
+
+{"description":"<!----{",
+"input":"<!----{",
+"output":["ParseError", "ParseError", ["Comment", "--{"]]},
+
+{"description":"<!----\\uDBC0\\uDC00",
+"input":"<!----\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["Comment", "--\uDBC0\uDC00"]]},
+
+{"description":"<!---.",
+"input":"<!---.",
+"output":["ParseError", ["Comment", "-."]]},
+
+{"description":"<!---/",
+"input":"<!---/",
+"output":["ParseError", ["Comment", "-/"]]},
+
+{"description":"<!---0",
+"input":"<!---0",
+"output":["ParseError", ["Comment", "-0"]]},
+
+{"description":"<!---1",
+"input":"<!---1",
+"output":["ParseError", ["Comment", "-1"]]},
+
+{"description":"<!---9",
+"input":"<!---9",
+"output":["ParseError", ["Comment", "-9"]]},
+
+{"description":"<!---<",
+"input":"<!---<",
+"output":["ParseError", ["Comment", "-<"]]},
+
+{"description":"<!---=",
+"input":"<!---=",
+"output":["ParseError", ["Comment", "-="]]},
+
+{"description":"<!--->",
+"input":"<!--->",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!---?",
+"input":"<!---?",
+"output":["ParseError", ["Comment", "-?"]]},
+
+{"description":"<!---@",
+"input":"<!---@",
+"output":["ParseError", ["Comment", "-@"]]},
+
+{"description":"<!---A",
+"input":"<!---A",
+"output":["ParseError", ["Comment", "-A"]]},
+
+{"description":"<!---B",
+"input":"<!---B",
+"output":["ParseError", ["Comment", "-B"]]},
+
+{"description":"<!---Y",
+"input":"<!---Y",
+"output":["ParseError", ["Comment", "-Y"]]},
+
+{"description":"<!---Z",
+"input":"<!---Z",
+"output":["ParseError", ["Comment", "-Z"]]},
+
+{"description":"<!---`",
+"input":"<!---`",
+"output":["ParseError", ["Comment", "-`"]]},
+
+{"description":"<!---a",
+"input":"<!---a",
+"output":["ParseError", ["Comment", "-a"]]},
+
+{"description":"<!---b",
+"input":"<!---b",
+"output":["ParseError", ["Comment", "-b"]]},
+
+{"description":"<!---y",
+"input":"<!---y",
+"output":["ParseError", ["Comment", "-y"]]},
+
+{"description":"<!---z",
+"input":"<!---z",
+"output":["ParseError", ["Comment", "-z"]]},
+
+{"description":"<!---{",
+"input":"<!---{",
+"output":["ParseError", ["Comment", "-{"]]},
+
+{"description":"<!---\\uDBC0\\uDC00",
+"input":"<!---\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "-\uDBC0\uDC00"]]},
+
+{"description":"<!--.",
+"input":"<!--.",
+"output":["ParseError", ["Comment", "."]]},
+
+{"description":"<!--/",
+"input":"<!--/",
+"output":["ParseError", ["Comment", "/"]]},
+
+{"description":"<!--0",
+"input":"<!--0",
+"output":["ParseError", ["Comment", "0"]]},
+
+{"description":"<!--1",
+"input":"<!--1",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"<!--9",
+"input":"<!--9",
+"output":["ParseError", ["Comment", "9"]]},
+
+{"description":"<!--<",
+"input":"<!--<",
+"output":["ParseError", ["Comment", "<"]]},
+
+{"description":"<!--=",
+"input":"<!--=",
+"output":["ParseError", ["Comment", "="]]},
+
+{"description":"<!-->",
+"input":"<!-->",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!--?",
+"input":"<!--?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<!--@",
+"input":"<!--@",
+"output":["ParseError", ["Comment", "@"]]},
+
+{"description":"<!--A",
+"input":"<!--A",
+"output":["ParseError", ["Comment", "A"]]},
+
+{"description":"<!--B",
+"input":"<!--B",
+"output":["ParseError", ["Comment", "B"]]},
+
+{"description":"<!--Y",
+"input":"<!--Y",
+"output":["ParseError", ["Comment", "Y"]]},
+
+{"description":"<!--Z",
+"input":"<!--Z",
+"output":["ParseError", ["Comment", "Z"]]},
+
+{"description":"<!--`",
+"input":"<!--`",
+"output":["ParseError", ["Comment", "`"]]},
+
+{"description":"<!--a",
+"input":"<!--a",
+"output":["ParseError", ["Comment", "a"]]},
+
+{"description":"<!--b",
+"input":"<!--b",
+"output":["ParseError", ["Comment", "b"]]},
+
+{"description":"<!--y",
+"input":"<!--y",
+"output":["ParseError", ["Comment", "y"]]},
+
+{"description":"<!--z",
+"input":"<!--z",
+"output":["ParseError", ["Comment", "z"]]},
+
+{"description":"<!--{",
+"input":"<!--{",
+"output":["ParseError", ["Comment", "{"]]},
+
+{"description":"<!--\\uDBC0\\uDC00",
+"input":"<!--\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "\uDBC0\uDC00"]]},
+
+{"description":"<!/",
+"input":"<!/",
+"output":["ParseError", ["Comment", "/"]]},
+
+{"description":"<!0",
+"input":"<!0",
+"output":["ParseError", ["Comment", "0"]]},
+
+{"description":"<!1",
+"input":"<!1",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"<!9",
+"input":"<!9",
+"output":["ParseError", ["Comment", "9"]]},
+
+{"description":"<!<",
+"input":"<!<",
+"output":["ParseError", ["Comment", "<"]]},
+
+{"description":"<!=",
+"input":"<!=",
+"output":["ParseError", ["Comment", "="]]},
+
+{"description":"<!>",
+"input":"<!>",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!?",
+"input":"<!?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<!@",
+"input":"<!@",
+"output":["ParseError", ["Comment", "@"]]},
+
+{"description":"<!A",
+"input":"<!A",
+"output":["ParseError", ["Comment", "A"]]},
+
+{"description":"<!B",
+"input":"<!B",
+"output":["ParseError", ["Comment", "B"]]},
+
+{"description":"<!DOCTYPE",
+"input":"<!DOCTYPE",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u0000",
+"input":"<!DOCTYPE\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u0008",
+"input":"<!DOCTYPE\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u0009",
+"input":"<!DOCTYPE\u0009",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000A",
+"input":"<!DOCTYPE\u000A",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000B",
+"input":"<!DOCTYPE\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000C",
+"input":"<!DOCTYPE\u000C",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000D",
+"input":"<!DOCTYPE\u000D",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u001F",
+"input":"<!DOCTYPE\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPE ",
+"input":"<!DOCTYPE ",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u0000",
+"input":"<!DOCTYPE \u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u0008",
+"input":"<!DOCTYPE \u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u0009",
+"input":"<!DOCTYPE \u0009",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000A",
+"input":"<!DOCTYPE \u000A",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000B",
+"input":"<!DOCTYPE \u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000C",
+"input":"<!DOCTYPE \u000C",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000D",
+"input":"<!DOCTYPE \u000D",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u001F",
+"input":"<!DOCTYPE \u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPE  ",
+"input":"<!DOCTYPE  ",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE !",
+"input":"<!DOCTYPE !",
+"output":["ParseError", ["DOCTYPE", "!", null, null, false]]},
+
+{"description":"<!DOCTYPE \"",
+"input":"<!DOCTYPE \"",
+"output":["ParseError", ["DOCTYPE", "\"", null, null, false]]},
+
+{"description":"<!DOCTYPE &",
+"input":"<!DOCTYPE &",
+"output":["ParseError", ["DOCTYPE", "&", null, null, false]]},
+
+{"description":"<!DOCTYPE '",
+"input":"<!DOCTYPE '",
+"output":["ParseError", ["DOCTYPE", "'", null, null, false]]},
+
+{"description":"<!DOCTYPE -",
+"input":"<!DOCTYPE -",
+"output":["ParseError", ["DOCTYPE", "-", null, null, false]]},
+
+{"description":"<!DOCTYPE /",
+"input":"<!DOCTYPE /",
+"output":["ParseError", ["DOCTYPE", "/", null, null, false]]},
+
+{"description":"<!DOCTYPE 0",
+"input":"<!DOCTYPE 0",
+"output":["ParseError", ["DOCTYPE", "0", null, null, false]]},
+
+{"description":"<!DOCTYPE 1",
+"input":"<!DOCTYPE 1",
+"output":["ParseError", ["DOCTYPE", "1", null, null, false]]},
+
+{"description":"<!DOCTYPE 9",
+"input":"<!DOCTYPE 9",
+"output":["ParseError", ["DOCTYPE", "9", null, null, false]]},
+
+{"description":"<!DOCTYPE <",
+"input":"<!DOCTYPE <",
+"output":["ParseError", ["DOCTYPE", "<", null, null, false]]},
+
+{"description":"<!DOCTYPE =",
+"input":"<!DOCTYPE =",
+"output":["ParseError", ["DOCTYPE", "=", null, null, false]]},
+
+{"description":"<!DOCTYPE >",
+"input":"<!DOCTYPE >",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE ?",
+"input":"<!DOCTYPE ?",
+"output":["ParseError", ["DOCTYPE", "?", null, null, false]]},
+
+{"description":"<!DOCTYPE @",
+"input":"<!DOCTYPE @",
+"output":["ParseError", ["DOCTYPE", "@", null, null, false]]},
+
+{"description":"<!DOCTYPE A",
+"input":"<!DOCTYPE A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE B",
+"input":"<!DOCTYPE B",
+"output":["ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPE Y",
+"input":"<!DOCTYPE Y",
+"output":["ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPE Z",
+"input":"<!DOCTYPE Z",
+"output":["ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE [",
+"input":"<!DOCTYPE [",
+"output":["ParseError", ["DOCTYPE", "[", null, null, false]]},
+
+{"description":"<!DOCTYPE `",
+"input":"<!DOCTYPE `",
+"output":["ParseError", ["DOCTYPE", "`", null, null, false]]},
+
+{"description":"<!DOCTYPE a",
+"input":"<!DOCTYPE a",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u0000",
+"input":"<!DOCTYPE a\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u0008",
+"input":"<!DOCTYPE a\u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u0009",
+"input":"<!DOCTYPE a\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000A",
+"input":"<!DOCTYPE a\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000B",
+"input":"<!DOCTYPE a\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000C",
+"input":"<!DOCTYPE a\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000D",
+"input":"<!DOCTYPE a\u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u001F",
+"input":"<!DOCTYPE a\u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPE a ",
+"input":"<!DOCTYPE a ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u0000",
+"input":"<!DOCTYPE a \u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u0008",
+"input":"<!DOCTYPE a \u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u0009",
+"input":"<!DOCTYPE a \u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000A",
+"input":"<!DOCTYPE a \u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000B",
+"input":"<!DOCTYPE a \u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000C",
+"input":"<!DOCTYPE a \u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000D",
+"input":"<!DOCTYPE a \u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u001F",
+"input":"<!DOCTYPE a \u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a  ",
+"input":"<!DOCTYPE a  ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a !",
+"input":"<!DOCTYPE a !",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \"",
+"input":"<!DOCTYPE a \"",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a &",
+"input":"<!DOCTYPE a &",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a '",
+"input":"<!DOCTYPE a '",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a -",
+"input":"<!DOCTYPE a -",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a /",
+"input":"<!DOCTYPE a /",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a 0",
+"input":"<!DOCTYPE a 0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a 1",
+"input":"<!DOCTYPE a 1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a 9",
+"input":"<!DOCTYPE a 9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a <",
+"input":"<!DOCTYPE a <",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a =",
+"input":"<!DOCTYPE a =",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a >",
+"input":"<!DOCTYPE a >",
+"output":[["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPE a ?",
+"input":"<!DOCTYPE a ?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a @",
+"input":"<!DOCTYPE a @",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a A",
+"input":"<!DOCTYPE a A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a B",
+"input":"<!DOCTYPE a B",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC",
+"input":"<!DOCTYPE a PUBLIC",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u0000",
+"input":"<!DOCTYPE a PUBLIC\u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u0008",
+"input":"<!DOCTYPE a PUBLIC\u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u0009",
+"input":"<!DOCTYPE a PUBLIC\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000A",
+"input":"<!DOCTYPE a PUBLIC\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000B",
+"input":"<!DOCTYPE a PUBLIC\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000C",
+"input":"<!DOCTYPE a PUBLIC\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000D",
+"input":"<!DOCTYPE a PUBLIC\u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u001F",
+"input":"<!DOCTYPE a PUBLIC\u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC ",
+"input":"<!DOCTYPE a PUBLIC ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC!",
+"input":"<!DOCTYPE a PUBLIC!",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"",
+"input":"<!DOCTYPE a PUBLIC\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u0000",
+"input":"<!DOCTYPE a PUBLIC\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u0009",
+"input":"<!DOCTYPE a PUBLIC\"\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u000A",
+"input":"<!DOCTYPE a PUBLIC\"\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u000B",
+"input":"<!DOCTYPE a PUBLIC\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u000C",
+"input":"<!DOCTYPE a PUBLIC\"\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\" ",
+"input":"<!DOCTYPE a PUBLIC\" ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"!",
+"input":"<!DOCTYPE a PUBLIC\"!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\"",
+"input":"<!DOCTYPE a PUBLIC\"\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"#",
+"input":"<!DOCTYPE a PUBLIC\"#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "#", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"&",
+"input":"<!DOCTYPE a PUBLIC\"&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"'",
+"input":"<!DOCTYPE a PUBLIC\"'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "'", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"-",
+"input":"<!DOCTYPE a PUBLIC\"-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"/",
+"input":"<!DOCTYPE a PUBLIC\"/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"0",
+"input":"<!DOCTYPE a PUBLIC\"0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"1",
+"input":"<!DOCTYPE a PUBLIC\"1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"9",
+"input":"<!DOCTYPE a PUBLIC\"9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"<",
+"input":"<!DOCTYPE a PUBLIC\"<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"=",
+"input":"<!DOCTYPE a PUBLIC\"=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\">",
+"input":"<!DOCTYPE a PUBLIC\">",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"?",
+"input":"<!DOCTYPE a PUBLIC\"?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"@",
+"input":"<!DOCTYPE a PUBLIC\"@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"A",
+"input":"<!DOCTYPE a PUBLIC\"A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"B",
+"input":"<!DOCTYPE a PUBLIC\"B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"Y",
+"input":"<!DOCTYPE a PUBLIC\"Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"Z",
+"input":"<!DOCTYPE a PUBLIC\"Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"`",
+"input":"<!DOCTYPE a PUBLIC\"`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"a",
+"input":"<!DOCTYPE a PUBLIC\"a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"b",
+"input":"<!DOCTYPE a PUBLIC\"b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"y",
+"input":"<!DOCTYPE a PUBLIC\"y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"z",
+"input":"<!DOCTYPE a PUBLIC\"z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"{",
+"input":"<!DOCTYPE a PUBLIC\"{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC#",
+"input":"<!DOCTYPE a PUBLIC#",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC&",
+"input":"<!DOCTYPE a PUBLIC&",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'",
+"input":"<!DOCTYPE a PUBLIC'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u0000",
+"input":"<!DOCTYPE a PUBLIC'\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u0009",
+"input":"<!DOCTYPE a PUBLIC'\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u000A",
+"input":"<!DOCTYPE a PUBLIC'\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u000B",
+"input":"<!DOCTYPE a PUBLIC'\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u000C",
+"input":"<!DOCTYPE a PUBLIC'\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC' ",
+"input":"<!DOCTYPE a PUBLIC' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'!",
+"input":"<!DOCTYPE a PUBLIC'!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\"",
+"input":"<!DOCTYPE a PUBLIC'\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\"", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'&",
+"input":"<!DOCTYPE a PUBLIC'&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''",
+"input":"<!DOCTYPE a PUBLIC''",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u0000",
+"input":"<!DOCTYPE a PUBLIC''\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u0008",
+"input":"<!DOCTYPE a PUBLIC''\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u0009",
+"input":"<!DOCTYPE a PUBLIC''\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000A",
+"input":"<!DOCTYPE a PUBLIC''\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000B",
+"input":"<!DOCTYPE a PUBLIC''\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000C",
+"input":"<!DOCTYPE a PUBLIC''\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000D",
+"input":"<!DOCTYPE a PUBLIC''\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u001F",
+"input":"<!DOCTYPE a PUBLIC''\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'' ",
+"input":"<!DOCTYPE a PUBLIC'' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''!",
+"input":"<!DOCTYPE a PUBLIC''!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\"",
+"input":"<!DOCTYPE a PUBLIC''\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''#",
+"input":"<!DOCTYPE a PUBLIC''#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''&",
+"input":"<!DOCTYPE a PUBLIC''&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'''",
+"input":"<!DOCTYPE a PUBLIC'''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''(",
+"input":"<!DOCTYPE a PUBLIC''(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''-",
+"input":"<!DOCTYPE a PUBLIC''-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''/",
+"input":"<!DOCTYPE a PUBLIC''/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''0",
+"input":"<!DOCTYPE a PUBLIC''0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''1",
+"input":"<!DOCTYPE a PUBLIC''1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''9",
+"input":"<!DOCTYPE a PUBLIC''9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''<",
+"input":"<!DOCTYPE a PUBLIC''<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''=",
+"input":"<!DOCTYPE a PUBLIC''=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''>",
+"input":"<!DOCTYPE a PUBLIC''>",
+"output":["ParseError", ["DOCTYPE", "a", "", null, true]]},
+
+{"description":"<!DOCTYPE a PUBLIC''?",
+"input":"<!DOCTYPE a PUBLIC''?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''@",
+"input":"<!DOCTYPE a PUBLIC''@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''A",
+"input":"<!DOCTYPE a PUBLIC''A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''B",
+"input":"<!DOCTYPE a PUBLIC''B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''Y",
+"input":"<!DOCTYPE a PUBLIC''Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''Z",
+"input":"<!DOCTYPE a PUBLIC''Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''`",
+"input":"<!DOCTYPE a PUBLIC''`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''a",
+"input":"<!DOCTYPE a PUBLIC''a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''b",
+"input":"<!DOCTYPE a PUBLIC''b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''y",
+"input":"<!DOCTYPE a PUBLIC''y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''z",
+"input":"<!DOCTYPE a PUBLIC''z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''{",
+"input":"<!DOCTYPE a PUBLIC''{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'(",
+"input":"<!DOCTYPE a PUBLIC'(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "(", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'-",
+"input":"<!DOCTYPE a PUBLIC'-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'/",
+"input":"<!DOCTYPE a PUBLIC'/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'0",
+"input":"<!DOCTYPE a PUBLIC'0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'1",
+"input":"<!DOCTYPE a PUBLIC'1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'9",
+"input":"<!DOCTYPE a PUBLIC'9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'<",
+"input":"<!DOCTYPE a PUBLIC'<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'=",
+"input":"<!DOCTYPE a PUBLIC'=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'>",
+"input":"<!DOCTYPE a PUBLIC'>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'?",
+"input":"<!DOCTYPE a PUBLIC'?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'@",
+"input":"<!DOCTYPE a PUBLIC'@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'A",
+"input":"<!DOCTYPE a PUBLIC'A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'B",
+"input":"<!DOCTYPE a PUBLIC'B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'Y",
+"input":"<!DOCTYPE a PUBLIC'Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'Z",
+"input":"<!DOCTYPE a PUBLIC'Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'`",
+"input":"<!DOCTYPE a PUBLIC'`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'a",
+"input":"<!DOCTYPE a PUBLIC'a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'b",
+"input":"<!DOCTYPE a PUBLIC'b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'y",
+"input":"<!DOCTYPE a PUBLIC'y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'z",
+"input":"<!DOCTYPE a PUBLIC'z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'{",
+"input":"<!DOCTYPE a PUBLIC'{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC(",
+"input":"<!DOCTYPE a PUBLIC(",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC-",
+"input":"<!DOCTYPE a PUBLIC-",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC/",
+"input":"<!DOCTYPE a PUBLIC/",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC0",
+"input":"<!DOCTYPE a PUBLIC0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC1",
+"input":"<!DOCTYPE a PUBLIC1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC9",
+"input":"<!DOCTYPE a PUBLIC9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC<",
+"input":"<!DOCTYPE a PUBLIC<",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC=",
+"input":"<!DOCTYPE a PUBLIC=",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC>",
+"input":"<!DOCTYPE a PUBLIC>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC?",
+"input":"<!DOCTYPE a PUBLIC?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC@",
+"input":"<!DOCTYPE a PUBLIC@",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICA",
+"input":"<!DOCTYPE a PUBLICA",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICB",
+"input":"<!DOCTYPE a PUBLICB",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICY",
+"input":"<!DOCTYPE a PUBLICY",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICZ",
+"input":"<!DOCTYPE a PUBLICZ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC`",
+"input":"<!DOCTYPE a PUBLIC`",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICa",
+"input":"<!DOCTYPE a PUBLICa",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICb",
+"input":"<!DOCTYPE a PUBLICb",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICy",
+"input":"<!DOCTYPE a PUBLICy",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICz",
+"input":"<!DOCTYPE a PUBLICz",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC{",
+"input":"<!DOCTYPE a PUBLIC{",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM",
+"input":"<!DOCTYPE a SYSTEM",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u0000",
+"input":"<!DOCTYPE a SYSTEM\u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u0008",
+"input":"<!DOCTYPE a SYSTEM\u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u0009",
+"input":"<!DOCTYPE a SYSTEM\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000A",
+"input":"<!DOCTYPE a SYSTEM\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000B",
+"input":"<!DOCTYPE a SYSTEM\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000C",
+"input":"<!DOCTYPE a SYSTEM\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000D",
+"input":"<!DOCTYPE a SYSTEM\u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u001F",
+"input":"<!DOCTYPE a SYSTEM\u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM ",
+"input":"<!DOCTYPE a SYSTEM ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM!",
+"input":"<!DOCTYPE a SYSTEM!",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"",
+"input":"<!DOCTYPE a SYSTEM\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u0000",
+"input":"<!DOCTYPE a SYSTEM\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u0009",
+"input":"<!DOCTYPE a SYSTEM\"\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u000A",
+"input":"<!DOCTYPE a SYSTEM\"\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u000B",
+"input":"<!DOCTYPE a SYSTEM\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u000C",
+"input":"<!DOCTYPE a SYSTEM\"\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\" ",
+"input":"<!DOCTYPE a SYSTEM\" ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"!",
+"input":"<!DOCTYPE a SYSTEM\"!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\"",
+"input":"<!DOCTYPE a SYSTEM\"\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"#",
+"input":"<!DOCTYPE a SYSTEM\"#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "#", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"&",
+"input":"<!DOCTYPE a SYSTEM\"&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"'",
+"input":"<!DOCTYPE a SYSTEM\"'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "'", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"-",
+"input":"<!DOCTYPE a SYSTEM\"-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"/",
+"input":"<!DOCTYPE a SYSTEM\"/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"0",
+"input":"<!DOCTYPE a SYSTEM\"0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"1",
+"input":"<!DOCTYPE a SYSTEM\"1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"9",
+"input":"<!DOCTYPE a SYSTEM\"9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"<",
+"input":"<!DOCTYPE a SYSTEM\"<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"=",
+"input":"<!DOCTYPE a SYSTEM\"=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\">",
+"input":"<!DOCTYPE a SYSTEM\">",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"?",
+"input":"<!DOCTYPE a SYSTEM\"?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"@",
+"input":"<!DOCTYPE a SYSTEM\"@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"A",
+"input":"<!DOCTYPE a SYSTEM\"A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"B",
+"input":"<!DOCTYPE a SYSTEM\"B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"Y",
+"input":"<!DOCTYPE a SYSTEM\"Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"Z",
+"input":"<!DOCTYPE a SYSTEM\"Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"`",
+"input":"<!DOCTYPE a SYSTEM\"`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"a",
+"input":"<!DOCTYPE a SYSTEM\"a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"b",
+"input":"<!DOCTYPE a SYSTEM\"b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"y",
+"input":"<!DOCTYPE a SYSTEM\"y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"z",
+"input":"<!DOCTYPE a SYSTEM\"z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"{",
+"input":"<!DOCTYPE a SYSTEM\"{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM#",
+"input":"<!DOCTYPE a SYSTEM#",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM&",
+"input":"<!DOCTYPE a SYSTEM&",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'",
+"input":"<!DOCTYPE a SYSTEM'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u0000",
+"input":"<!DOCTYPE a SYSTEM'\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u0009",
+"input":"<!DOCTYPE a SYSTEM'\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u000A",
+"input":"<!DOCTYPE a SYSTEM'\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u000B",
+"input":"<!DOCTYPE a SYSTEM'\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u000C",
+"input":"<!DOCTYPE a SYSTEM'\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM' ",
+"input":"<!DOCTYPE a SYSTEM' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'!",
+"input":"<!DOCTYPE a SYSTEM'!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\"",
+"input":"<!DOCTYPE a SYSTEM'\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\"", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'&",
+"input":"<!DOCTYPE a SYSTEM'&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''",
+"input":"<!DOCTYPE a SYSTEM''",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u0000",
+"input":"<!DOCTYPE a SYSTEM''\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u0008",
+"input":"<!DOCTYPE a SYSTEM''\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u0009",
+"input":"<!DOCTYPE a SYSTEM''\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000A",
+"input":"<!DOCTYPE a SYSTEM''\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000B",
+"input":"<!DOCTYPE a SYSTEM''\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000C",
+"input":"<!DOCTYPE a SYSTEM''\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000D",
+"input":"<!DOCTYPE a SYSTEM''\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u001F",
+"input":"<!DOCTYPE a SYSTEM''\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM'' ",
+"input":"<!DOCTYPE a SYSTEM'' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''!",
+"input":"<!DOCTYPE a SYSTEM''!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\"",
+"input":"<!DOCTYPE a SYSTEM''\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''&",
+"input":"<!DOCTYPE a SYSTEM''&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM'''",
+"input":"<!DOCTYPE a SYSTEM'''",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''-",
+"input":"<!DOCTYPE a SYSTEM''-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''/",
+"input":"<!DOCTYPE a SYSTEM''/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''0",
+"input":"<!DOCTYPE a SYSTEM''0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''1",
+"input":"<!DOCTYPE a SYSTEM''1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''9",
+"input":"<!DOCTYPE a SYSTEM''9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''<",
+"input":"<!DOCTYPE a SYSTEM''<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''=",
+"input":"<!DOCTYPE a SYSTEM''=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''>",
+"input":"<!DOCTYPE a SYSTEM''>",
+"output":["ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''?",
+"input":"<!DOCTYPE a SYSTEM''?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''@",
+"input":"<!DOCTYPE a SYSTEM''@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''A",
+"input":"<!DOCTYPE a SYSTEM''A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''B",
+"input":"<!DOCTYPE a SYSTEM''B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''Y",
+"input":"<!DOCTYPE a SYSTEM''Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''Z",
+"input":"<!DOCTYPE a SYSTEM''Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''`",
+"input":"<!DOCTYPE a SYSTEM''`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''a",
+"input":"<!DOCTYPE a SYSTEM''a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''b",
+"input":"<!DOCTYPE a SYSTEM''b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''y",
+"input":"<!DOCTYPE a SYSTEM''y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''z",
+"input":"<!DOCTYPE a SYSTEM''z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''{",
+"input":"<!DOCTYPE a SYSTEM''{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM'(",
+"input":"<!DOCTYPE a SYSTEM'(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "(", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'-",
+"input":"<!DOCTYPE a SYSTEM'-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'/",
+"input":"<!DOCTYPE a SYSTEM'/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'0",
+"input":"<!DOCTYPE a SYSTEM'0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'1",
+"input":"<!DOCTYPE a SYSTEM'1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'9",
+"input":"<!DOCTYPE a SYSTEM'9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'<",
+"input":"<!DOCTYPE a SYSTEM'<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'=",
+"input":"<!DOCTYPE a SYSTEM'=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'>",
+"input":"<!DOCTYPE a SYSTEM'>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'?",
+"input":"<!DOCTYPE a SYSTEM'?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'@",
+"input":"<!DOCTYPE a SYSTEM'@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'A",
+"input":"<!DOCTYPE a SYSTEM'A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'B",
+"input":"<!DOCTYPE a SYSTEM'B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'Y",
+"input":"<!DOCTYPE a SYSTEM'Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'Z",
+"input":"<!DOCTYPE a SYSTEM'Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'`",
+"input":"<!DOCTYPE a SYSTEM'`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'a",
+"input":"<!DOCTYPE a SYSTEM'a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'b",
+"input":"<!DOCTYPE a SYSTEM'b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'y",
+"input":"<!DOCTYPE a SYSTEM'y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'z",
+"input":"<!DOCTYPE a SYSTEM'z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'{",
+"input":"<!DOCTYPE a SYSTEM'{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM(",
+"input":"<!DOCTYPE a SYSTEM(",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM-",
+"input":"<!DOCTYPE a SYSTEM-",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM/",
+"input":"<!DOCTYPE a SYSTEM/",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM0",
+"input":"<!DOCTYPE a SYSTEM0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM1",
+"input":"<!DOCTYPE a SYSTEM1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM9",
+"input":"<!DOCTYPE a SYSTEM9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM<",
+"input":"<!DOCTYPE a SYSTEM<",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM=",
+"input":"<!DOCTYPE a SYSTEM=",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM>",
+"input":"<!DOCTYPE a SYSTEM>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM?",
+"input":"<!DOCTYPE a SYSTEM?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM@",
+"input":"<!DOCTYPE a SYSTEM@",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMA",
+"input":"<!DOCTYPE a SYSTEMA",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMB",
+"input":"<!DOCTYPE a SYSTEMB",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMY",
+"input":"<!DOCTYPE a SYSTEMY",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMZ",
+"input":"<!DOCTYPE a SYSTEMZ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM`",
+"input":"<!DOCTYPE a SYSTEM`",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMa",
+"input":"<!DOCTYPE a SYSTEMa",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMb",
+"input":"<!DOCTYPE a SYSTEMb",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMy",
+"input":"<!DOCTYPE a SYSTEMy",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMz",
+"input":"<!DOCTYPE a SYSTEMz",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM{",
+"input":"<!DOCTYPE a SYSTEM{",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a Y",
+"input":"<!DOCTYPE a Y",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a Z",
+"input":"<!DOCTYPE a Z",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a `",
+"input":"<!DOCTYPE a `",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a",
+"input":"<!DOCTYPE a a",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u0000",
+"input":"<!DOCTYPE a a\u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u0009",
+"input":"<!DOCTYPE a a\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u000A",
+"input":"<!DOCTYPE a a\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u000B",
+"input":"<!DOCTYPE a a\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u000C",
+"input":"<!DOCTYPE a a\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a ",
+"input":"<!DOCTYPE a a ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a!",
+"input":"<!DOCTYPE a a!",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\"",
+"input":"<!DOCTYPE a a\"",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a&",
+"input":"<!DOCTYPE a a&",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a'",
+"input":"<!DOCTYPE a a'",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a-",
+"input":"<!DOCTYPE a a-",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a/",
+"input":"<!DOCTYPE a a/",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a0",
+"input":"<!DOCTYPE a a0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a1",
+"input":"<!DOCTYPE a a1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a9",
+"input":"<!DOCTYPE a a9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a<",
+"input":"<!DOCTYPE a a<",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a=",
+"input":"<!DOCTYPE a a=",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a>",
+"input":"<!DOCTYPE a a>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a?",
+"input":"<!DOCTYPE a a?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a@",
+"input":"<!DOCTYPE a a@",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aA",
+"input":"<!DOCTYPE a aA",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aB",
+"input":"<!DOCTYPE a aB",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aY",
+"input":"<!DOCTYPE a aY",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aZ",
+"input":"<!DOCTYPE a aZ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a`",
+"input":"<!DOCTYPE a a`",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aa",
+"input":"<!DOCTYPE a aa",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a ab",
+"input":"<!DOCTYPE a ab",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a ay",
+"input":"<!DOCTYPE a ay",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a az",
+"input":"<!DOCTYPE a az",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a{",
+"input":"<!DOCTYPE a a{",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a a\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a b",
+"input":"<!DOCTYPE a b",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a y",
+"input":"<!DOCTYPE a y",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a z",
+"input":"<!DOCTYPE a z",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a {",
+"input":"<!DOCTYPE a {",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\uDBC0\\uDC00",
+"input":"<!DOCTYPE a \uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a!",
+"input":"<!DOCTYPE a!",
+"output":["ParseError", ["DOCTYPE", "a!", null, null, false]]},
+
+{"description":"<!DOCTYPE a\"",
+"input":"<!DOCTYPE a\"",
+"output":["ParseError", ["DOCTYPE", "a\"", null, null, false]]},
+
+{"description":"<!DOCTYPE a&",
+"input":"<!DOCTYPE a&",
+"output":["ParseError", ["DOCTYPE", "a&", null, null, false]]},
+
+{"description":"<!DOCTYPE a'",
+"input":"<!DOCTYPE a'",
+"output":["ParseError", ["DOCTYPE", "a'", null, null, false]]},
+
+{"description":"<!DOCTYPE a-",
+"input":"<!DOCTYPE a-",
+"output":["ParseError", ["DOCTYPE", "a-", null, null, false]]},
+
+{"description":"<!DOCTYPE a/",
+"input":"<!DOCTYPE a/",
+"output":["ParseError", ["DOCTYPE", "a/", null, null, false]]},
+
+{"description":"<!DOCTYPE a0",
+"input":"<!DOCTYPE a0",
+"output":["ParseError", ["DOCTYPE", "a0", null, null, false]]},
+
+{"description":"<!DOCTYPE a1",
+"input":"<!DOCTYPE a1",
+"output":["ParseError", ["DOCTYPE", "a1", null, null, false]]},
+
+{"description":"<!DOCTYPE a9",
+"input":"<!DOCTYPE a9",
+"output":["ParseError", ["DOCTYPE", "a9", null, null, false]]},
+
+{"description":"<!DOCTYPE a<",
+"input":"<!DOCTYPE a<",
+"output":["ParseError", ["DOCTYPE", "a<", null, null, false]]},
+
+{"description":"<!DOCTYPE a=",
+"input":"<!DOCTYPE a=",
+"output":["ParseError", ["DOCTYPE", "a=", null, null, false]]},
+
+{"description":"<!DOCTYPE a>",
+"input":"<!DOCTYPE a>",
+"output":[["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPE a?",
+"input":"<!DOCTYPE a?",
+"output":["ParseError", ["DOCTYPE", "a?", null, null, false]]},
+
+{"description":"<!DOCTYPE a@",
+"input":"<!DOCTYPE a@",
+"output":["ParseError", ["DOCTYPE", "a@", null, null, false]]},
+
+{"description":"<!DOCTYPE aA",
+"input":"<!DOCTYPE aA",
+"output":["ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPE aB",
+"input":"<!DOCTYPE aB",
+"output":["ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPE aY",
+"input":"<!DOCTYPE aY",
+"output":["ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPE aZ",
+"input":"<!DOCTYPE aZ",
+"output":["ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPE a[",
+"input":"<!DOCTYPE a[",
+"output":["ParseError", ["DOCTYPE", "a[", null, null, false]]},
+
+{"description":"<!DOCTYPE a`",
+"input":"<!DOCTYPE a`",
+"output":["ParseError", ["DOCTYPE", "a`", null, null, false]]},
+
+{"description":"<!DOCTYPE aa",
+"input":"<!DOCTYPE aa",
+"output":["ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPE ab",
+"input":"<!DOCTYPE ab",
+"output":["ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPE ay",
+"input":"<!DOCTYPE ay",
+"output":["ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPE az",
+"input":"<!DOCTYPE az",
+"output":["ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPE a{",
+"input":"<!DOCTYPE a{",
+"output":["ParseError", ["DOCTYPE", "a{", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!DOCTYPE b",
+"input":"<!DOCTYPE b",
+"output":["ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPE y",
+"input":"<!DOCTYPE y",
+"output":["ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPE z",
+"input":"<!DOCTYPE z",
+"output":["ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE {",
+"input":"<!DOCTYPE {",
+"output":["ParseError", ["DOCTYPE", "{", null, null, false]]},
+
+{"description":"<!DOCTYPE \\uDBC0\\uDC00",
+"input":"<!DOCTYPE \uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!DOCTYPE!",
+"input":"<!DOCTYPE!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "!", null, null, false]]},
+
+{"description":"<!DOCTYPE\"",
+"input":"<!DOCTYPE\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\"", null, null, false]]},
+
+{"description":"<!DOCTYPE&",
+"input":"<!DOCTYPE&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "&", null, null, false]]},
+
+{"description":"<!DOCTYPE'",
+"input":"<!DOCTYPE'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "'", null, null, false]]},
+
+{"description":"<!DOCTYPE-",
+"input":"<!DOCTYPE-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "-", null, null, false]]},
+
+{"description":"<!DOCTYPE/",
+"input":"<!DOCTYPE/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "/", null, null, false]]},
+
+{"description":"<!DOCTYPE0",
+"input":"<!DOCTYPE0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "0", null, null, false]]},
+
+{"description":"<!DOCTYPE1",
+"input":"<!DOCTYPE1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "1", null, null, false]]},
+
+{"description":"<!DOCTYPE9",
+"input":"<!DOCTYPE9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "9", null, null, false]]},
+
+{"description":"<!DOCTYPE<",
+"input":"<!DOCTYPE<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "<", null, null, false]]},
+
+{"description":"<!DOCTYPE=",
+"input":"<!DOCTYPE=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "=", null, null, false]]},
+
+{"description":"<!DOCTYPE>",
+"input":"<!DOCTYPE>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE?",
+"input":"<!DOCTYPE?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "?", null, null, false]]},
+
+{"description":"<!DOCTYPE@",
+"input":"<!DOCTYPE@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "@", null, null, false]]},
+
+{"description":"<!DOCTYPEA",
+"input":"<!DOCTYPEA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEB",
+"input":"<!DOCTYPEB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPEY",
+"input":"<!DOCTYPEY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPEZ",
+"input":"<!DOCTYPEZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE`",
+"input":"<!DOCTYPE`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "`", null, null, false]]},
+
+{"description":"<!DOCTYPEa",
+"input":"<!DOCTYPEa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u0000",
+"input":"<!DOCTYPEa\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u0008",
+"input":"<!DOCTYPEa\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u0009",
+"input":"<!DOCTYPEa\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000A",
+"input":"<!DOCTYPEa\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000B",
+"input":"<!DOCTYPEa\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000C",
+"input":"<!DOCTYPEa\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000D",
+"input":"<!DOCTYPEa\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u001F",
+"input":"<!DOCTYPEa\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPEa ",
+"input":"<!DOCTYPEa ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u0000",
+"input":"<!DOCTYPEa \u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u0008",
+"input":"<!DOCTYPEa \u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u0009",
+"input":"<!DOCTYPEa \u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000A",
+"input":"<!DOCTYPEa \u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000B",
+"input":"<!DOCTYPEa \u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000C",
+"input":"<!DOCTYPEa \u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000D",
+"input":"<!DOCTYPEa \u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u001F",
+"input":"<!DOCTYPEa \u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa  ",
+"input":"<!DOCTYPEa  ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa !",
+"input":"<!DOCTYPEa !",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \"",
+"input":"<!DOCTYPEa \"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa &",
+"input":"<!DOCTYPEa &",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa '",
+"input":"<!DOCTYPEa '",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa -",
+"input":"<!DOCTYPEa -",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa /",
+"input":"<!DOCTYPEa /",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa 0",
+"input":"<!DOCTYPEa 0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa 1",
+"input":"<!DOCTYPEa 1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa 9",
+"input":"<!DOCTYPEa 9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa <",
+"input":"<!DOCTYPEa <",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa =",
+"input":"<!DOCTYPEa =",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa >",
+"input":"<!DOCTYPEa >",
+"output":["ParseError", ["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPEa ?",
+"input":"<!DOCTYPEa ?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa @",
+"input":"<!DOCTYPEa @",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa A",
+"input":"<!DOCTYPEa A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa B",
+"input":"<!DOCTYPEa B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC",
+"input":"<!DOCTYPEa PUBLIC",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u0000",
+"input":"<!DOCTYPEa PUBLIC\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u0008",
+"input":"<!DOCTYPEa PUBLIC\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u0009",
+"input":"<!DOCTYPEa PUBLIC\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000A",
+"input":"<!DOCTYPEa PUBLIC\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000B",
+"input":"<!DOCTYPEa PUBLIC\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000C",
+"input":"<!DOCTYPEa PUBLIC\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000D",
+"input":"<!DOCTYPEa PUBLIC\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u001F",
+"input":"<!DOCTYPEa PUBLIC\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC ",
+"input":"<!DOCTYPEa PUBLIC ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC!",
+"input":"<!DOCTYPEa PUBLIC!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"",
+"input":"<!DOCTYPEa PUBLIC\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u0000",
+"input":"<!DOCTYPEa PUBLIC\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u0009",
+"input":"<!DOCTYPEa PUBLIC\"\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u000A",
+"input":"<!DOCTYPEa PUBLIC\"\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u000B",
+"input":"<!DOCTYPEa PUBLIC\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u000C",
+"input":"<!DOCTYPEa PUBLIC\"\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\" ",
+"input":"<!DOCTYPEa PUBLIC\" ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"!",
+"input":"<!DOCTYPEa PUBLIC\"!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\"",
+"input":"<!DOCTYPEa PUBLIC\"\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"#",
+"input":"<!DOCTYPEa PUBLIC\"#",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "#", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"&",
+"input":"<!DOCTYPEa PUBLIC\"&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"'",
+"input":"<!DOCTYPEa PUBLIC\"'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "'", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"-",
+"input":"<!DOCTYPEa PUBLIC\"-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"/",
+"input":"<!DOCTYPEa PUBLIC\"/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"0",
+"input":"<!DOCTYPEa PUBLIC\"0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"1",
+"input":"<!DOCTYPEa PUBLIC\"1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"9",
+"input":"<!DOCTYPEa PUBLIC\"9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"<",
+"input":"<!DOCTYPEa PUBLIC\"<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"=",
+"input":"<!DOCTYPEa PUBLIC\"=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\">",
+"input":"<!DOCTYPEa PUBLIC\">",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"?",
+"input":"<!DOCTYPEa PUBLIC\"?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"@",
+"input":"<!DOCTYPEa PUBLIC\"@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"A",
+"input":"<!DOCTYPEa PUBLIC\"A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"B",
+"input":"<!DOCTYPEa PUBLIC\"B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"Y",
+"input":"<!DOCTYPEa PUBLIC\"Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"Z",
+"input":"<!DOCTYPEa PUBLIC\"Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"`",
+"input":"<!DOCTYPEa PUBLIC\"`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"a",
+"input":"<!DOCTYPEa PUBLIC\"a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"b",
+"input":"<!DOCTYPEa PUBLIC\"b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"y",
+"input":"<!DOCTYPEa PUBLIC\"y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"z",
+"input":"<!DOCTYPEa PUBLIC\"z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"{",
+"input":"<!DOCTYPEa PUBLIC\"{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC#",
+"input":"<!DOCTYPEa PUBLIC#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC&",
+"input":"<!DOCTYPEa PUBLIC&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'",
+"input":"<!DOCTYPEa PUBLIC'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u0000",
+"input":"<!DOCTYPEa PUBLIC'\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u0009",
+"input":"<!DOCTYPEa PUBLIC'\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u000A",
+"input":"<!DOCTYPEa PUBLIC'\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u000B",
+"input":"<!DOCTYPEa PUBLIC'\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u000C",
+"input":"<!DOCTYPEa PUBLIC'\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC' ",
+"input":"<!DOCTYPEa PUBLIC' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'!",
+"input":"<!DOCTYPEa PUBLIC'!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\"",
+"input":"<!DOCTYPEa PUBLIC'\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\"", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'&",
+"input":"<!DOCTYPEa PUBLIC'&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''",
+"input":"<!DOCTYPEa PUBLIC''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u0000",
+"input":"<!DOCTYPEa PUBLIC''\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u0008",
+"input":"<!DOCTYPEa PUBLIC''\u0008",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u0009",
+"input":"<!DOCTYPEa PUBLIC''\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000A",
+"input":"<!DOCTYPEa PUBLIC''\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000B",
+"input":"<!DOCTYPEa PUBLIC''\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000C",
+"input":"<!DOCTYPEa PUBLIC''\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000D",
+"input":"<!DOCTYPEa PUBLIC''\u000D",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u001F",
+"input":"<!DOCTYPEa PUBLIC''\u001F",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'' ",
+"input":"<!DOCTYPEa PUBLIC'' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''!",
+"input":"<!DOCTYPEa PUBLIC''!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\"",
+"input":"<!DOCTYPEa PUBLIC''\"",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''#",
+"input":"<!DOCTYPEa PUBLIC''#",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''&",
+"input":"<!DOCTYPEa PUBLIC''&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'''",
+"input":"<!DOCTYPEa PUBLIC'''",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''(",
+"input":"<!DOCTYPEa PUBLIC''(",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''-",
+"input":"<!DOCTYPEa PUBLIC''-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''/",
+"input":"<!DOCTYPEa PUBLIC''/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''0",
+"input":"<!DOCTYPEa PUBLIC''0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''1",
+"input":"<!DOCTYPEa PUBLIC''1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''9",
+"input":"<!DOCTYPEa PUBLIC''9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''<",
+"input":"<!DOCTYPEa PUBLIC''<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''=",
+"input":"<!DOCTYPEa PUBLIC''=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''>",
+"input":"<!DOCTYPEa PUBLIC''>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, true]]},
+
+{"description":"<!DOCTYPEa PUBLIC''?",
+"input":"<!DOCTYPEa PUBLIC''?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''@",
+"input":"<!DOCTYPEa PUBLIC''@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''A",
+"input":"<!DOCTYPEa PUBLIC''A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''B",
+"input":"<!DOCTYPEa PUBLIC''B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''Y",
+"input":"<!DOCTYPEa PUBLIC''Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''Z",
+"input":"<!DOCTYPEa PUBLIC''Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''`",
+"input":"<!DOCTYPEa PUBLIC''`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''a",
+"input":"<!DOCTYPEa PUBLIC''a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''b",
+"input":"<!DOCTYPEa PUBLIC''b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''y",
+"input":"<!DOCTYPEa PUBLIC''y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''z",
+"input":"<!DOCTYPEa PUBLIC''z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''{",
+"input":"<!DOCTYPEa PUBLIC''{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'(",
+"input":"<!DOCTYPEa PUBLIC'(",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "(", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'-",
+"input":"<!DOCTYPEa PUBLIC'-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'/",
+"input":"<!DOCTYPEa PUBLIC'/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'0",
+"input":"<!DOCTYPEa PUBLIC'0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'1",
+"input":"<!DOCTYPEa PUBLIC'1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'9",
+"input":"<!DOCTYPEa PUBLIC'9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'<",
+"input":"<!DOCTYPEa PUBLIC'<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'=",
+"input":"<!DOCTYPEa PUBLIC'=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'>",
+"input":"<!DOCTYPEa PUBLIC'>",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'?",
+"input":"<!DOCTYPEa PUBLIC'?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'@",
+"input":"<!DOCTYPEa PUBLIC'@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'A",
+"input":"<!DOCTYPEa PUBLIC'A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'B",
+"input":"<!DOCTYPEa PUBLIC'B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'Y",
+"input":"<!DOCTYPEa PUBLIC'Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'Z",
+"input":"<!DOCTYPEa PUBLIC'Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'`",
+"input":"<!DOCTYPEa PUBLIC'`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'a",
+"input":"<!DOCTYPEa PUBLIC'a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'b",
+"input":"<!DOCTYPEa PUBLIC'b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'y",
+"input":"<!DOCTYPEa PUBLIC'y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'z",
+"input":"<!DOCTYPEa PUBLIC'z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'{",
+"input":"<!DOCTYPEa PUBLIC'{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC(",
+"input":"<!DOCTYPEa PUBLIC(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC-",
+"input":"<!DOCTYPEa PUBLIC-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC/",
+"input":"<!DOCTYPEa PUBLIC/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC0",
+"input":"<!DOCTYPEa PUBLIC0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC1",
+"input":"<!DOCTYPEa PUBLIC1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC9",
+"input":"<!DOCTYPEa PUBLIC9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC<",
+"input":"<!DOCTYPEa PUBLIC<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC=",
+"input":"<!DOCTYPEa PUBLIC=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC>",
+"input":"<!DOCTYPEa PUBLIC>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC?",
+"input":"<!DOCTYPEa PUBLIC?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC@",
+"input":"<!DOCTYPEa PUBLIC@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICA",
+"input":"<!DOCTYPEa PUBLICA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICB",
+"input":"<!DOCTYPEa PUBLICB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICY",
+"input":"<!DOCTYPEa PUBLICY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICZ",
+"input":"<!DOCTYPEa PUBLICZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC`",
+"input":"<!DOCTYPEa PUBLIC`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICa",
+"input":"<!DOCTYPEa PUBLICa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICb",
+"input":"<!DOCTYPEa PUBLICb",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICy",
+"input":"<!DOCTYPEa PUBLICy",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICz",
+"input":"<!DOCTYPEa PUBLICz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC{",
+"input":"<!DOCTYPEa PUBLIC{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM",
+"input":"<!DOCTYPEa SYSTEM",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u0000",
+"input":"<!DOCTYPEa SYSTEM\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u0008",
+"input":"<!DOCTYPEa SYSTEM\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u0009",
+"input":"<!DOCTYPEa SYSTEM\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000A",
+"input":"<!DOCTYPEa SYSTEM\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000B",
+"input":"<!DOCTYPEa SYSTEM\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000C",
+"input":"<!DOCTYPEa SYSTEM\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000D",
+"input":"<!DOCTYPEa SYSTEM\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u001F",
+"input":"<!DOCTYPEa SYSTEM\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM ",
+"input":"<!DOCTYPEa SYSTEM ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM!",
+"input":"<!DOCTYPEa SYSTEM!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"",
+"input":"<!DOCTYPEa SYSTEM\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u0000",
+"input":"<!DOCTYPEa SYSTEM\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u0009",
+"input":"<!DOCTYPEa SYSTEM\"\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u000A",
+"input":"<!DOCTYPEa SYSTEM\"\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u000B",
+"input":"<!DOCTYPEa SYSTEM\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u000C",
+"input":"<!DOCTYPEa SYSTEM\"\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\" ",
+"input":"<!DOCTYPEa SYSTEM\" ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"!",
+"input":"<!DOCTYPEa SYSTEM\"!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\"",
+"input":"<!DOCTYPEa SYSTEM\"\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"#",
+"input":"<!DOCTYPEa SYSTEM\"#",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "#", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"&",
+"input":"<!DOCTYPEa SYSTEM\"&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"'",
+"input":"<!DOCTYPEa SYSTEM\"'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "'", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"-",
+"input":"<!DOCTYPEa SYSTEM\"-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"/",
+"input":"<!DOCTYPEa SYSTEM\"/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"0",
+"input":"<!DOCTYPEa SYSTEM\"0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"1",
+"input":"<!DOCTYPEa SYSTEM\"1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"9",
+"input":"<!DOCTYPEa SYSTEM\"9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"<",
+"input":"<!DOCTYPEa SYSTEM\"<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"=",
+"input":"<!DOCTYPEa SYSTEM\"=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\">",
+"input":"<!DOCTYPEa SYSTEM\">",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"?",
+"input":"<!DOCTYPEa SYSTEM\"?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"@",
+"input":"<!DOCTYPEa SYSTEM\"@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"A",
+"input":"<!DOCTYPEa SYSTEM\"A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"B",
+"input":"<!DOCTYPEa SYSTEM\"B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"Y",
+"input":"<!DOCTYPEa SYSTEM\"Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"Z",
+"input":"<!DOCTYPEa SYSTEM\"Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"`",
+"input":"<!DOCTYPEa SYSTEM\"`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"a",
+"input":"<!DOCTYPEa SYSTEM\"a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"b",
+"input":"<!DOCTYPEa SYSTEM\"b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"y",
+"input":"<!DOCTYPEa SYSTEM\"y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"z",
+"input":"<!DOCTYPEa SYSTEM\"z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"{",
+"input":"<!DOCTYPEa SYSTEM\"{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM#",
+"input":"<!DOCTYPEa SYSTEM#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM&",
+"input":"<!DOCTYPEa SYSTEM&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'",
+"input":"<!DOCTYPEa SYSTEM'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u0000",
+"input":"<!DOCTYPEa SYSTEM'\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u0009",
+"input":"<!DOCTYPEa SYSTEM'\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u000A",
+"input":"<!DOCTYPEa SYSTEM'\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u000B",
+"input":"<!DOCTYPEa SYSTEM'\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u000C",
+"input":"<!DOCTYPEa SYSTEM'\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM' ",
+"input":"<!DOCTYPEa SYSTEM' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'!",
+"input":"<!DOCTYPEa SYSTEM'!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\"",
+"input":"<!DOCTYPEa SYSTEM'\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\"", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'&",
+"input":"<!DOCTYPEa SYSTEM'&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''",
+"input":"<!DOCTYPEa SYSTEM''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u0000",
+"input":"<!DOCTYPEa SYSTEM''\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u0008",
+"input":"<!DOCTYPEa SYSTEM''\u0008",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u0009",
+"input":"<!DOCTYPEa SYSTEM''\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000A",
+"input":"<!DOCTYPEa SYSTEM''\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000B",
+"input":"<!DOCTYPEa SYSTEM''\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000C",
+"input":"<!DOCTYPEa SYSTEM''\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000D",
+"input":"<!DOCTYPEa SYSTEM''\u000D",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u001F",
+"input":"<!DOCTYPEa SYSTEM''\u001F",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM'' ",
+"input":"<!DOCTYPEa SYSTEM'' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''!",
+"input":"<!DOCTYPEa SYSTEM''!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\"",
+"input":"<!DOCTYPEa SYSTEM''\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''&",
+"input":"<!DOCTYPEa SYSTEM''&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM'''",
+"input":"<!DOCTYPEa SYSTEM'''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''-",
+"input":"<!DOCTYPEa SYSTEM''-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''/",
+"input":"<!DOCTYPEa SYSTEM''/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''0",
+"input":"<!DOCTYPEa SYSTEM''0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''1",
+"input":"<!DOCTYPEa SYSTEM''1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''9",
+"input":"<!DOCTYPEa SYSTEM''9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''<",
+"input":"<!DOCTYPEa SYSTEM''<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''=",
+"input":"<!DOCTYPEa SYSTEM''=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''>",
+"input":"<!DOCTYPEa SYSTEM''>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''?",
+"input":"<!DOCTYPEa SYSTEM''?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''@",
+"input":"<!DOCTYPEa SYSTEM''@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''A",
+"input":"<!DOCTYPEa SYSTEM''A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''B",
+"input":"<!DOCTYPEa SYSTEM''B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''Y",
+"input":"<!DOCTYPEa SYSTEM''Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''Z",
+"input":"<!DOCTYPEa SYSTEM''Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''`",
+"input":"<!DOCTYPEa SYSTEM''`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''a",
+"input":"<!DOCTYPEa SYSTEM''a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''b",
+"input":"<!DOCTYPEa SYSTEM''b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''y",
+"input":"<!DOCTYPEa SYSTEM''y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''z",
+"input":"<!DOCTYPEa SYSTEM''z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''{",
+"input":"<!DOCTYPEa SYSTEM''{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM'(",
+"input":"<!DOCTYPEa SYSTEM'(",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "(", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'-",
+"input":"<!DOCTYPEa SYSTEM'-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'/",
+"input":"<!DOCTYPEa SYSTEM'/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'0",
+"input":"<!DOCTYPEa SYSTEM'0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'1",
+"input":"<!DOCTYPEa SYSTEM'1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'9",
+"input":"<!DOCTYPEa SYSTEM'9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'<",
+"input":"<!DOCTYPEa SYSTEM'<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'=",
+"input":"<!DOCTYPEa SYSTEM'=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'>",
+"input":"<!DOCTYPEa SYSTEM'>",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'?",
+"input":"<!DOCTYPEa SYSTEM'?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'@",
+"input":"<!DOCTYPEa SYSTEM'@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'A",
+"input":"<!DOCTYPEa SYSTEM'A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'B",
+"input":"<!DOCTYPEa SYSTEM'B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'Y",
+"input":"<!DOCTYPEa SYSTEM'Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'Z",
+"input":"<!DOCTYPEa SYSTEM'Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'`",
+"input":"<!DOCTYPEa SYSTEM'`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'a",
+"input":"<!DOCTYPEa SYSTEM'a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'b",
+"input":"<!DOCTYPEa SYSTEM'b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'y",
+"input":"<!DOCTYPEa SYSTEM'y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'z",
+"input":"<!DOCTYPEa SYSTEM'z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'{",
+"input":"<!DOCTYPEa SYSTEM'{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM(",
+"input":"<!DOCTYPEa SYSTEM(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM-",
+"input":"<!DOCTYPEa SYSTEM-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM/",
+"input":"<!DOCTYPEa SYSTEM/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM0",
+"input":"<!DOCTYPEa SYSTEM0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM1",
+"input":"<!DOCTYPEa SYSTEM1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM9",
+"input":"<!DOCTYPEa SYSTEM9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM<",
+"input":"<!DOCTYPEa SYSTEM<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM=",
+"input":"<!DOCTYPEa SYSTEM=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM>",
+"input":"<!DOCTYPEa SYSTEM>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM?",
+"input":"<!DOCTYPEa SYSTEM?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM@",
+"input":"<!DOCTYPEa SYSTEM@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMA",
+"input":"<!DOCTYPEa SYSTEMA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMB",
+"input":"<!DOCTYPEa SYSTEMB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMY",
+"input":"<!DOCTYPEa SYSTEMY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMZ",
+"input":"<!DOCTYPEa SYSTEMZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM`",
+"input":"<!DOCTYPEa SYSTEM`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMa",
+"input":"<!DOCTYPEa SYSTEMa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMb",
+"input":"<!DOCTYPEa SYSTEMb",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMy",
+"input":"<!DOCTYPEa SYSTEMy",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMz",
+"input":"<!DOCTYPEa SYSTEMz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM{",
+"input":"<!DOCTYPEa SYSTEM{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa Y",
+"input":"<!DOCTYPEa Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa Z",
+"input":"<!DOCTYPEa Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa `",
+"input":"<!DOCTYPEa `",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a",
+"input":"<!DOCTYPEa a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u0000",
+"input":"<!DOCTYPEa a\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u0009",
+"input":"<!DOCTYPEa a\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u000A",
+"input":"<!DOCTYPEa a\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u000B",
+"input":"<!DOCTYPEa a\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u000C",
+"input":"<!DOCTYPEa a\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a ",
+"input":"<!DOCTYPEa a ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a!",
+"input":"<!DOCTYPEa a!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\"",
+"input":"<!DOCTYPEa a\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a&",
+"input":"<!DOCTYPEa a&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a'",
+"input":"<!DOCTYPEa a'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a-",
+"input":"<!DOCTYPEa a-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a/",
+"input":"<!DOCTYPEa a/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a0",
+"input":"<!DOCTYPEa a0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a1",
+"input":"<!DOCTYPEa a1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a9",
+"input":"<!DOCTYPEa a9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a<",
+"input":"<!DOCTYPEa a<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a=",
+"input":"<!DOCTYPEa a=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a>",
+"input":"<!DOCTYPEa a>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a?",
+"input":"<!DOCTYPEa a?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a@",
+"input":"<!DOCTYPEa a@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aA",
+"input":"<!DOCTYPEa aA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aB",
+"input":"<!DOCTYPEa aB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aY",
+"input":"<!DOCTYPEa aY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aZ",
+"input":"<!DOCTYPEa aZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a`",
+"input":"<!DOCTYPEa a`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aa",
+"input":"<!DOCTYPEa aa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa ab",
+"input":"<!DOCTYPEa ab",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa ay",
+"input":"<!DOCTYPEa ay",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa az",
+"input":"<!DOCTYPEa az",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a{",
+"input":"<!DOCTYPEa a{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa a\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa b",
+"input":"<!DOCTYPEa b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa y",
+"input":"<!DOCTYPEa y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa z",
+"input":"<!DOCTYPEa z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa {",
+"input":"<!DOCTYPEa {",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\uDBC0\\uDC00",
+"input":"<!DOCTYPEa \uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa!",
+"input":"<!DOCTYPEa!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a!", null, null, false]]},
+
+{"description":"<!DOCTYPEa\"",
+"input":"<!DOCTYPEa\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\"", null, null, false]]},
+
+{"description":"<!DOCTYPEa&",
+"input":"<!DOCTYPEa&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a&", null, null, false]]},
+
+{"description":"<!DOCTYPEa'",
+"input":"<!DOCTYPEa'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a'", null, null, false]]},
+
+{"description":"<!DOCTYPEa-",
+"input":"<!DOCTYPEa-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a-", null, null, false]]},
+
+{"description":"<!DOCTYPEa/",
+"input":"<!DOCTYPEa/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a/", null, null, false]]},
+
+{"description":"<!DOCTYPEa0",
+"input":"<!DOCTYPEa0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a0", null, null, false]]},
+
+{"description":"<!DOCTYPEa1",
+"input":"<!DOCTYPEa1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a1", null, null, false]]},
+
+{"description":"<!DOCTYPEa9",
+"input":"<!DOCTYPEa9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a9", null, null, false]]},
+
+{"description":"<!DOCTYPEa<",
+"input":"<!DOCTYPEa<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a<", null, null, false]]},
+
+{"description":"<!DOCTYPEa=",
+"input":"<!DOCTYPEa=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a=", null, null, false]]},
+
+{"description":"<!DOCTYPEa>",
+"input":"<!DOCTYPEa>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPEa?",
+"input":"<!DOCTYPEa?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a?", null, null, false]]},
+
+{"description":"<!DOCTYPEa@",
+"input":"<!DOCTYPEa@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a@", null, null, false]]},
+
+{"description":"<!DOCTYPEaA",
+"input":"<!DOCTYPEaA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPEaB",
+"input":"<!DOCTYPEaB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPEaY",
+"input":"<!DOCTYPEaY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPEaZ",
+"input":"<!DOCTYPEaZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPEa[",
+"input":"<!DOCTYPEa[",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a[", null, null, false]]},
+
+{"description":"<!DOCTYPEa`",
+"input":"<!DOCTYPEa`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a`", null, null, false]]},
+
+{"description":"<!DOCTYPEaa",
+"input":"<!DOCTYPEaa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPEab",
+"input":"<!DOCTYPEab",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPEay",
+"input":"<!DOCTYPEay",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPEaz",
+"input":"<!DOCTYPEaz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPEa{",
+"input":"<!DOCTYPEa{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a{", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!DOCTYPEb",
+"input":"<!DOCTYPEb",
+"output":["ParseError", "ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPEy",
+"input":"<!DOCTYPEy",
+"output":["ParseError", "ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPEz",
+"input":"<!DOCTYPEz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE{",
+"input":"<!DOCTYPE{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "{", null, null, false]]},
+
+{"description":"<!DOCTYPE\\uDBC0\\uDC00",
+"input":"<!DOCTYPE\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!Y",
+"input":"<!Y",
+"output":["ParseError", ["Comment", "Y"]]},
+
+{"description":"<!Z",
+"input":"<!Z",
+"output":["ParseError", ["Comment", "Z"]]},
+
+{"description":"<!`",
+"input":"<!`",
+"output":["ParseError", ["Comment", "`"]]},
+
+{"description":"<!a",
+"input":"<!a",
+"output":["ParseError", ["Comment", "a"]]},
+
+{"description":"<!b",
+"input":"<!b",
+"output":["ParseError", ["Comment", "b"]]},
+
+{"description":"<!y",
+"input":"<!y",
+"output":["ParseError", ["Comment", "y"]]},
+
+{"description":"<!z",
+"input":"<!z",
+"output":["ParseError", ["Comment", "z"]]},
+
+{"description":"<!{",
+"input":"<!{",
+"output":["ParseError", ["Comment", "{"]]},
+
+{"description":"<!\\uDBC0\\uDC00",
+"input":"<!\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "\uDBC0\uDC00"]]},
+
+{"description":"<\"",
+"input":"<\"",
+"output":["ParseError", ["Character", "<\""]]},
+
+{"description":"<&",
+"input":"<&",
+"output":["ParseError", ["Character", "<&"]]},
+
+{"description":"<'",
+"input":"<'",
+"output":["ParseError", ["Character", "<'"]]},
+
+{"description":"<-",
+"input":"<-",
+"output":["ParseError", ["Character", "<-"]]},
+
+{"description":"<.",
+"input":"<.",
+"output":["ParseError", ["Character", "<."]]},
+
+{"description":"</",
+"input":"</",
+"output":["ParseError", ["Character", "</"]]},
+
+{"description":"</\\u0000",
+"input":"</\u0000",
+"output":["ParseError", ["Comment", "\uFFFD"]]},
+
+{"description":"</\\u0009",
+"input":"</\u0009",
+"output":["ParseError", ["Comment", "\u0009"]]},
+
+{"description":"</\\u000A",
+"input":"</\u000A",
+"output":["ParseError", ["Comment", "\u000A"]]},
+
+{"description":"</\\u000B",
+"input":"</\u000B",
+"output":["ParseError", "ParseError", ["Comment", "\u000B"]]},
+
+{"description":"</\\u000C",
+"input":"</\u000C",
+"output":["ParseError", ["Comment", "\u000C"]]},
+
+{"description":"</ ",
+"input":"</ ",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"</!",
+"input":"</!",
+"output":["ParseError", ["Comment", "!"]]},
+
+{"description":"</\"",
+"input":"</\"",
+"output":["ParseError", ["Comment", "\""]]},
+
+{"description":"</&",
+"input":"</&",
+"output":["ParseError", ["Comment", "&"]]},
+
+{"description":"</'",
+"input":"</'",
+"output":["ParseError", ["Comment", "'"]]},
+
+{"description":"</-",
+"input":"</-",
+"output":["ParseError", ["Comment", "-"]]},
+
+{"description":"<//",
+"input":"<//",
+"output":["ParseError", ["Comment", "/"]]},
+
+{"description":"</0",
+"input":"</0",
+"output":["ParseError", ["Comment", "0"]]},
+
+{"description":"</1",
+"input":"</1",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"</9",
+"input":"</9",
+"output":["ParseError", ["Comment", "9"]]},
+
+{"description":"</<",
+"input":"</<",
+"output":["ParseError", ["Comment", "<"]]},
+
+{"description":"</=",
+"input":"</=",
+"output":["ParseError", ["Comment", "="]]},
+
+{"description":"</>",
+"input":"</>",
+"output":["ParseError"]},
+
+{"description":"</?",
+"input":"</?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"</@",
+"input":"</@",
+"output":["ParseError", ["Comment", "@"]]},
+
+{"description":"</A>",
+"input":"</A>",
+"output":[["EndTag", "a"]]},
+
+{"description":"</B>",
+"input":"</B>",
+"output":[["EndTag", "b"]]},
+
+{"description":"</Y>",
+"input":"</Y>",
+"output":[["EndTag", "y"]]},
+
+{"description":"</Z>",
+"input":"</Z>",
+"output":[["EndTag", "z"]]},
+
+{"description":"</[",
+"input":"</[",
+"output":["ParseError", ["Comment", "["]]},
+
+{"description":"</`",
+"input":"</`",
+"output":["ParseError", ["Comment", "`"]]},
+
+{"description":"</a>",
+"input":"</a>",
+"output":[["EndTag", "a"]]},
+
+{"description":"</b>",
+"input":"</b>",
+"output":[["EndTag", "b"]]},
+
+{"description":"</y>",
+"input":"</y>",
+"output":[["EndTag", "y"]]},
+
+{"description":"</z>",
+"input":"</z>",
+"output":[["EndTag", "z"]]},
+
+{"description":"</{",
+"input":"</{",
+"output":["ParseError", ["Comment", "{"]]},
+
+{"description":"</\\uDBC0\\uDC00",
+"input":"</\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "\uDBC0\uDC00"]]},
+
+{"description":"<0",
+"input":"<0",
+"output":["ParseError", ["Character", "<0"]]},
+
+{"description":"<1",
+"input":"<1",
+"output":["ParseError", ["Character", "<1"]]},
+
+{"description":"<9",
+"input":"<9",
+"output":["ParseError", ["Character", "<9"]]},
+
+{"description":"<<",
+"input":"<<",
+"output":["ParseError", ["Character", "<"], "ParseError", ["Character", "<"]]},
+
+{"description":"<=",
+"input":"<=",
+"output":["ParseError", ["Character", "<="]]},
+
+{"description":"<>",
+"input":"<>",
+"output":["ParseError", ["Character", "<>"]]},
+
+{"description":"<?",
+"input":"<?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<?\\u0000",
+"input":"<?\u0000",
+"output":["ParseError", ["Comment", "?\uFFFD"]]},
+
+{"description":"<?\\u0009",
+"input":"<?\u0009",
+"output":["ParseError", ["Comment", "?\u0009"]]},
+
+{"description":"<?\\u000A",
+"input":"<?\u000A",
+"output":["ParseError", ["Comment", "?\u000A"]]},
+
+{"description":"<?\\u000B",
+"input":"<?\u000B",
+"output":["ParseError", "ParseError", ["Comment", "?\u000B"]]},
+
+{"description":"<?\\u000C",
+"input":"<?\u000C",
+"output":["ParseError", ["Comment", "?\u000C"]]},
+
+{"description":"<? ",
+"input":"<? ",
+"output":["ParseError", ["Comment", "? "]]},
+
+{"description":"<?!",
+"input":"<?!",
+"output":["ParseError", ["Comment", "?!"]]},
+
+{"description":"<?\"",
+"input":"<?\"",
+"output":["ParseError", ["Comment", "?\""]]},
+
+{"description":"<?&",
+"input":"<?&",
+"output":["ParseError", ["Comment", "?&"]]},
+
+{"description":"<?'",
+"input":"<?'",
+"output":["ParseError", ["Comment", "?'"]]},
+
+{"description":"<?-",
+"input":"<?-",
+"output":["ParseError", ["Comment", "?-"]]},
+
+{"description":"<?/",
+"input":"<?/",
+"output":["ParseError", ["Comment", "?/"]]},
+
+{"description":"<?0",
+"input":"<?0",
+"output":["ParseError", ["Comment", "?0"]]},
+
+{"description":"<?1",
+"input":"<?1",
+"output":["ParseError", ["Comment", "?1"]]},
+
+{"description":"<?9",
+"input":"<?9",
+"output":["ParseError", ["Comment", "?9"]]},
+
+{"description":"<?<",
+"input":"<?<",
+"output":["ParseError", ["Comment", "?<"]]},
+
+{"description":"<?=",
+"input":"<?=",
+"output":["ParseError", ["Comment", "?="]]},
+
+{"description":"<?>",
+"input":"<?>",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<??",
+"input":"<??",
+"output":["ParseError", ["Comment", "??"]]},
+
+{"description":"<?@",
+"input":"<?@",
+"output":["ParseError", ["Comment", "?@"]]},
+
+{"description":"<?A",
+"input":"<?A",
+"output":["ParseError", ["Comment", "?A"]]},
+
+{"description":"<?B",
+"input":"<?B",
+"output":["ParseError", ["Comment", "?B"]]},
+
+{"description":"<?Y",
+"input":"<?Y",
+"output":["ParseError", ["Comment", "?Y"]]},
+
+{"description":"<?Z",
+"input":"<?Z",
+"output":["ParseError", ["Comment", "?Z"]]},
+
+{"description":"<?`",
+"input":"<?`",
+"output":["ParseError", ["Comment", "?`"]]},
+
+{"description":"<?a",
+"input":"<?a",
+"output":["ParseError", ["Comment", "?a"]]},
+
+{"description":"<?b",
+"input":"<?b",
+"output":["ParseError", ["Comment", "?b"]]},
+
+{"description":"<?y",
+"input":"<?y",
+"output":["ParseError", ["Comment", "?y"]]},
+
+{"description":"<?z",
+"input":"<?z",
+"output":["ParseError", ["Comment", "?z"]]},
+
+{"description":"<?{",
+"input":"<?{",
+"output":["ParseError", ["Comment", "?{"]]},
+
+{"description":"<?\\uDBC0\\uDC00",
+"input":"<?\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "?\uDBC0\uDC00"]]},
+
+{"description":"<@",
+"input":"<@",
+"output":["ParseError", ["Character", "<@"]]},
+
+{"description":"<A>",
+"input":"<A>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<B>",
+"input":"<B>",
+"output":[["StartTag", "b", {}]]},
+
+{"description":"<Y>",
+"input":"<Y>",
+"output":[["StartTag", "y", {}]]},
+
+{"description":"<Z>",
+"input":"<Z>",
+"output":[["StartTag", "z", {}]]},
+
+{"description":"<[",
+"input":"<[",
+"output":["ParseError", ["Character", "<["]]},
+
+{"description":"<`",
+"input":"<`",
+"output":["ParseError", ["Character", "<`"]]},
+
+{"description":"<a>",
+"input":"<a>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u0000>",
+"input":"<a\u0000>",
+"output":["ParseError", ["StartTag", "a\uFFFD", {}]]},
+
+{"description":"<a\\u0008>",
+"input":"<a\u0008>",
+"output":["ParseError", ["StartTag", "a\u0008", {}]]},
+
+{"description":"<a\\u0009>",
+"input":"<a\u0009>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u000A>",
+"input":"<a\u000A>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u000B>",
+"input":"<a\u000B>",
+"output":["ParseError", ["StartTag", "a\u000B", {}]]},
+
+{"description":"<a\\u000C>",
+"input":"<a\u000C>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u000D>",
+"input":"<a\u000D>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u001F>",
+"input":"<a\u001F>",
+"output":["ParseError", ["StartTag", "a\u001F", {}]]},
+
+{"description":"<a >",
+"input":"<a >",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u0000>",
+"input":"<a \u0000>",
+"output":["ParseError", ["StartTag", "a", {"\uFFFD":""}]]},
+
+{"description":"<a \\u0008>",
+"input":"<a \u0008>",
+"output":["ParseError", ["StartTag", "a", {"\u0008":""}]]},
+
+{"description":"<a \\u0009>",
+"input":"<a \u0009>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u000A>",
+"input":"<a \u000A>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u000B>",
+"input":"<a \u000B>",
+"output":["ParseError", ["StartTag", "a", {"\u000B":""}]]},
+
+{"description":"<a \\u000C>",
+"input":"<a \u000C>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u000D>",
+"input":"<a \u000D>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u001F>",
+"input":"<a \u001F>",
+"output":["ParseError", ["StartTag", "a", {"\u001F":""}]]},
+
+{"description":"<a  >",
+"input":"<a  >",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a !>",
+"input":"<a !>",
+"output":[["StartTag", "a", {"!":""}]]},
+
+{"description":"<a \">",
+"input":"<a \">",
+"output":["ParseError", ["StartTag", "a", {"\"":""}]]},
+
+{"description":"<a #>",
+"input":"<a #>",
+"output":[["StartTag", "a", {"#":""}]]},
+
+{"description":"<a &>",
+"input":"<a &>",
+"output":[["StartTag", "a", {"&":""}]]},
+
+{"description":"<a '>",
+"input":"<a '>",
+"output":["ParseError", ["StartTag", "a", {"'":""}]]},
+
+{"description":"<a (>",
+"input":"<a (>",
+"output":[["StartTag", "a", {"(":""}]]},
+
+{"description":"<a ->",
+"input":"<a ->",
+"output":[["StartTag", "a", {"-":""}]]},
+
+{"description":"<a .>",
+"input":"<a .>",
+"output":[["StartTag", "a", {".":""}]]},
+
+{"description":"<a />",
+"input":"<a />",
+"output":[["StartTag", "a", {}, true]]},
+
+{"description":"<a 0>",
+"input":"<a 0>",
+"output":[["StartTag", "a", {"0":""}]]},
+
+{"description":"<a 1>",
+"input":"<a 1>",
+"output":[["StartTag", "a", {"1":""}]]},
+
+{"description":"<a 9>",
+"input":"<a 9>",
+"output":[["StartTag", "a", {"9":""}]]},
+
+{"description":"<a <>",
+"input":"<a <>",
+"output":["ParseError", ["StartTag", "a", {"<":""}]]},
+
+{"description":"<a =>",
+"input":"<a =>",
+"output":["ParseError", ["StartTag", "a", {"=":""}]]},
+
+{"description":"<a >",
+"input":"<a >",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a ?>",
+"input":"<a ?>",
+"output":[["StartTag", "a", {"?":""}]]},
+
+{"description":"<a @>",
+"input":"<a @>",
+"output":[["StartTag", "a", {"@":""}]]},
+
+{"description":"<a A>",
+"input":"<a A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a B>",
+"input":"<a B>",
+"output":[["StartTag", "a", {"b":""}]]},
+
+{"description":"<a Y>",
+"input":"<a Y>",
+"output":[["StartTag", "a", {"y":""}]]},
+
+{"description":"<a Z>",
+"input":"<a Z>",
+"output":[["StartTag", "a", {"z":""}]]},
+
+{"description":"<a [>",
+"input":"<a [>",
+"output":[["StartTag", "a", {"[":""}]]},
+
+{"description":"<a `>",
+"input":"<a `>",
+"output":[["StartTag", "a", {"`":""}]]},
+
+{"description":"<a a>",
+"input":"<a a>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u0000>",
+"input":"<a a\u0000>",
+"output":["ParseError", ["StartTag", "a", {"a\uFFFD":""}]]},
+
+{"description":"<a a\\u0008>",
+"input":"<a a\u0008>",
+"output":["ParseError", ["StartTag", "a", {"a\u0008":""}]]},
+
+{"description":"<a a\\u0009>",
+"input":"<a a\u0009>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u000A>",
+"input":"<a a\u000A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u000B>",
+"input":"<a a\u000B>",
+"output":["ParseError", ["StartTag", "a", {"a\u000B":""}]]},
+
+{"description":"<a a\\u000C>",
+"input":"<a a\u000C>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u000D>",
+"input":"<a a\u000D>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u001F>",
+"input":"<a a\u001F>",
+"output":["ParseError", ["StartTag", "a", {"a\u001F":""}]]},
+
+{"description":"<a a >",
+"input":"<a a >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u0000>",
+"input":"<a a \u0000>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\uFFFD":""}]]},
+
+{"description":"<a a \\u0008>",
+"input":"<a a \u0008>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\u0008":""}]]},
+
+{"description":"<a a \\u0009>",
+"input":"<a a \u0009>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u000A>",
+"input":"<a a \u000A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u000B>",
+"input":"<a a \u000B>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\u000B":""}]]},
+
+{"description":"<a a \\u000C>",
+"input":"<a a \u000C>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u000D>",
+"input":"<a a \u000D>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u001F>",
+"input":"<a a \u001F>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\u001F":""}]]},
+
+{"description":"<a a  >",
+"input":"<a a  >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a !>",
+"input":"<a a !>",
+"output":[["StartTag", "a", {"a":"", "!":""}]]},
+
+{"description":"<a a \">",
+"input":"<a a \">",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\"":""}]]},
+
+{"description":"<a a #>",
+"input":"<a a #>",
+"output":[["StartTag", "a", {"a":"", "#":""}]]},
+
+{"description":"<a a &>",
+"input":"<a a &>",
+"output":[["StartTag", "a", {"a":"", "&":""}]]},
+
+{"description":"<a a '>",
+"input":"<a a '>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "'":""}]]},
+
+{"description":"<a a (>",
+"input":"<a a (>",
+"output":[["StartTag", "a", {"a":"", "(":""}]]},
+
+{"description":"<a a ->",
+"input":"<a a ->",
+"output":[["StartTag", "a", {"a":"", "-":""}]]},
+
+{"description":"<a a .>",
+"input":"<a a .>",
+"output":[["StartTag", "a", {"a":"", ".":""}]]},
+
+{"description":"<a a />",
+"input":"<a a />",
+"output":[["StartTag", "a", {"a":""}, true]]},
+
+{"description":"<a a 0>",
+"input":"<a a 0>",
+"output":[["StartTag", "a", {"a":"", "0":""}]]},
+
+{"description":"<a a 1>",
+"input":"<a a 1>",
+"output":[["StartTag", "a", {"a":"", "1":""}]]},
+
+{"description":"<a a 9>",
+"input":"<a a 9>",
+"output":[["StartTag", "a", {"a":"", "9":""}]]},
+
+{"description":"<a a <>",
+"input":"<a a <>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "<":""}]]},
+
+{"description":"<a a =>",
+"input":"<a a =>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a >",
+"input":"<a a >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a ?>",
+"input":"<a a ?>",
+"output":[["StartTag", "a", {"a":"", "?":""}]]},
+
+{"description":"<a a @>",
+"input":"<a a @>",
+"output":[["StartTag", "a", {"a":"", "@":""}]]},
+
+{"description":"<a a A>",
+"input":"<a a A>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a B>",
+"input":"<a a B>",
+"output":[["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a Y>",
+"input":"<a a Y>",
+"output":[["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a Z>",
+"input":"<a a Z>",
+"output":[["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a [>",
+"input":"<a a [>",
+"output":[["StartTag", "a", {"a":"", "[":""}]]},
+
+{"description":"<a a `>",
+"input":"<a a `>",
+"output":[["StartTag", "a", {"a":"", "`":""}]]},
+
+{"description":"<a a a>",
+"input":"<a a a>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a b>",
+"input":"<a a b>",
+"output":[["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a y>",
+"input":"<a a y>",
+"output":[["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a z>",
+"input":"<a a z>",
+"output":[["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a {>",
+"input":"<a a {>",
+"output":[["StartTag", "a", {"a":"", "{":""}]]},
+
+{"description":"<a a \\uDBC0\\uDC00>",
+"input":"<a a \uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a":"", "\uDBC0\uDC00":""}]]},
+
+{"description":"<a a!>",
+"input":"<a a!>",
+"output":[["StartTag", "a", {"a!":""}]]},
+
+{"description":"<a a\">",
+"input":"<a a\">",
+"output":["ParseError", ["StartTag", "a", {"a\"":""}]]},
+
+{"description":"<a a#>",
+"input":"<a a#>",
+"output":[["StartTag", "a", {"a#":""}]]},
+
+{"description":"<a a&>",
+"input":"<a a&>",
+"output":[["StartTag", "a", {"a&":""}]]},
+
+{"description":"<a a'>",
+"input":"<a a'>",
+"output":["ParseError", ["StartTag", "a", {"a'":""}]]},
+
+{"description":"<a a(>",
+"input":"<a a(>",
+"output":[["StartTag", "a", {"a(":""}]]},
+
+{"description":"<a a->",
+"input":"<a a->",
+"output":[["StartTag", "a", {"a-":""}]]},
+
+{"description":"<a a.>",
+"input":"<a a.>",
+"output":[["StartTag", "a", {"a.":""}]]},
+
+{"description":"<a a/>",
+"input":"<a a/>",
+"output":[["StartTag", "a", {"a":""}, true]]},
+
+{"description":"<a a0>",
+"input":"<a a0>",
+"output":[["StartTag", "a", {"a0":""}]]},
+
+{"description":"<a a1>",
+"input":"<a a1>",
+"output":[["StartTag", "a", {"a1":""}]]},
+
+{"description":"<a a9>",
+"input":"<a a9>",
+"output":[["StartTag", "a", {"a9":""}]]},
+
+{"description":"<a a<>",
+"input":"<a a<>",
+"output":["ParseError", ["StartTag", "a", {"a<":""}]]},
+
+{"description":"<a a=>",
+"input":"<a a=>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u0000>",
+"input":"<a a=\u0000>",
+"output":["ParseError", ["StartTag", "a", {"a":"\uFFFD"}]]},
+
+{"description":"<a a=\\u0008>",
+"input":"<a a=\u0008>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u0008"}]]},
+
+{"description":"<a a=\\u0009>",
+"input":"<a a=\u0009>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u000A>",
+"input":"<a a=\u000A>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u000B>",
+"input":"<a a=\u000B>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u000B"}]]},
+
+{"description":"<a a=\\u000C>",
+"input":"<a a=\u000C>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u000D>",
+"input":"<a a=\u000D>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u001F>",
+"input":"<a a=\u001F>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u001F"}]]},
+
+{"description":"<a a= >",
+"input":"<a a= >",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=!>",
+"input":"<a a=!>",
+"output":[["StartTag", "a", {"a":"!"}]]},
+
+{"description":"<a a=\"\">",
+"input":"<a a=\"\">",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\"\\u0000\">",
+"input":"<a a=\"\u0000\">",
+"output":["ParseError", ["StartTag", "a", {"a":"\uFFFD"}]]},
+
+{"description":"<a a=\"\\u0009\">",
+"input":"<a a=\"\u0009\">",
+"output":[["StartTag", "a", {"a":"\u0009"}]]},
+
+{"description":"<a a=\"\\u000A\">",
+"input":"<a a=\"\u000A\">",
+"output":[["StartTag", "a", {"a":"\u000A"}]]},
+
+{"description":"<a a=\"\\u000B\">",
+"input":"<a a=\"\u000B\">",
+"output":["ParseError", ["StartTag", "a", {"a":"\u000B"}]]},
+
+{"description":"<a a=\"\\u000C\">",
+"input":"<a a=\"\u000C\">",
+"output":[["StartTag", "a", {"a":"\u000C"}]]},
+
+{"description":"<a a=\" \">",
+"input":"<a a=\" \">",
+"output":[["StartTag", "a", {"a":" "}]]},
+
+{"description":"<a a=\"!\">",
+"input":"<a a=\"!\">",
+"output":[["StartTag", "a", {"a":"!"}]]},
+
+{"description":"<a a=\"\">",
+"input":"<a a=\"\">",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\"#\">",
+"input":"<a a=\"#\">",
+"output":[["StartTag", "a", {"a":"#"}]]},
+
+{"description":"<a a=\"%\">",
+"input":"<a a=\"%\">",
+"output":[["StartTag", "a", {"a":"%"}]]},
+
+{"description":"<a a=\"&\">",
+"input":"<a a=\"&\">",
+"output":[["StartTag", "a", {"a":"&"}]]},
+
+{"description":"<a a=\"'\">",
+"input":"<a a=\"'\">",
+"output":[["StartTag", "a", {"a":"'"}]]},
+
+{"description":"<a a=\"-\">",
+"input":"<a a=\"-\">",
+"output":[["StartTag", "a", {"a":"-"}]]},
+
+{"description":"<a a=\"/\">",
+"input":"<a a=\"/\">",
+"output":[["StartTag", "a", {"a":"/"}]]},
+
+{"description":"<a a=\"0\">",
+"input":"<a a=\"0\">",
+"output":[["StartTag", "a", {"a":"0"}]]},
+
+{"description":"<a a=\"1\">",
+"input":"<a a=\"1\">",
+"output":[["StartTag", "a", {"a":"1"}]]},
+
+{"description":"<a a=\"9\">",
+"input":"<a a=\"9\">",
+"output":[["StartTag", "a", {"a":"9"}]]},
+
+{"description":"<a a=\"<\">",
+"input":"<a a=\"<\">",
+"output":[["StartTag", "a", {"a":"<"}]]},
+
+{"description":"<a a=\"=\">",
+"input":"<a a=\"=\">",
+"output":[["StartTag", "a", {"a":"="}]]},
+
+{"description":"<a a=\">\">",
+"input":"<a a=\">\">",
+"output":[["StartTag", "a", {"a":">"}]]},
+
+{"description":"<a a=\"?\">",
+"input":"<a a=\"?\">",
+"output":[["StartTag", "a", {"a":"?"}]]},
+
+{"description":"<a a=\"@\">",
+"input":"<a a=\"@\">",
+"output":[["StartTag", "a", {"a":"@"}]]},
+
+{"description":"<a a=\"A\">",
+"input":"<a a=\"A\">",
+"output":[["StartTag", "a", {"a":"A"}]]},
+
+{"description":"<a a=\"B\">",
+"input":"<a a=\"B\">",
+"output":[["StartTag", "a", {"a":"B"}]]},
+
+{"description":"<a a=\"Y\">",
+"input":"<a a=\"Y\">",
+"output":[["StartTag", "a", {"a":"Y"}]]},
+
+{"description":"<a a=\"Z\">",
+"input":"<a a=\"Z\">",
+"output":[["StartTag", "a", {"a":"Z"}]]},
+
+{"description":"<a a=\"`\">",
+"input":"<a a=\"`\">",
+"output":[["StartTag", "a", {"a":"`"}]]},
+
+{"description":"<a a=\"a\">",
+"input":"<a a=\"a\">",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=\"b\">",
+"input":"<a a=\"b\">",
+"output":[["StartTag", "a", {"a":"b"}]]},
+
+{"description":"<a a=\"y\">",
+"input":"<a a=\"y\">",
+"output":[["StartTag", "a", {"a":"y"}]]},
+
+{"description":"<a a=\"z\">",
+"input":"<a a=\"z\">",
+"output":[["StartTag", "a", {"a":"z"}]]},
+
+{"description":"<a a=\"{\">",
+"input":"<a a=\"{\">",
+"output":[["StartTag", "a", {"a":"{"}]]},
+
+{"description":"<a a=\"\\uDBC0\\uDC00\">",
+"input":"<a a=\"\uDBC0\uDC00\">",
+"output":[["StartTag", "a", {"a":"\uDBC0\uDC00"}]]},
+
+{"description":"<a a=#>",
+"input":"<a a=#>",
+"output":[["StartTag", "a", {"a":"#"}]]},
+
+{"description":"<a a=%>",
+"input":"<a a=%>",
+"output":[["StartTag", "a", {"a":"%"}]]},
+
+{"description":"<a a=&>",
+"input":"<a a=&>",
+"output":[["StartTag", "a", {"a":"&"}]]},
+
+{"description":"<a a=''>",
+"input":"<a a=''>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a='\\u0000'>",
+"input":"<a a='\u0000'>",
+"output":["ParseError", ["StartTag", "a", {"a":"\uFFFD"}]]},
+
+{"description":"<a a='\\u0009'>",
+"input":"<a a='\u0009'>",
+"output":[["StartTag", "a", {"a":"\u0009"}]]},
+
+{"description":"<a a='\\u000A'>",
+"input":"<a a='\u000A'>",
+"output":[["StartTag", "a", {"a":"\u000A"}]]},
+
+{"description":"<a a='\\u000B'>",
+"input":"<a a='\u000B'>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u000B"}]]},
+
+{"description":"<a a='\\u000C'>",
+"input":"<a a='\u000C'>",
+"output":[["StartTag", "a", {"a":"\u000C"}]]},
+
+{"description":"<a a=' '>",
+"input":"<a a=' '>",
+"output":[["StartTag", "a", {"a":" "}]]},
+
+{"description":"<a a='!'>",
+"input":"<a a='!'>",
+"output":[["StartTag", "a", {"a":"!"}]]},
+
+{"description":"<a a='\"'>",
+"input":"<a a='\"'>",
+"output":[["StartTag", "a", {"a":"\""}]]},
+
+{"description":"<a a='%'>",
+"input":"<a a='%'>",
+"output":[["StartTag", "a", {"a":"%"}]]},
+
+{"description":"<a a='&'>",
+"input":"<a a='&'>",
+"output":[["StartTag", "a", {"a":"&"}]]},
+
+{"description":"<a a=''>",
+"input":"<a a=''>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u0000>",
+"input":"<a a=''\u0000>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\uFFFD":""}]]},
+
+{"description":"<a a=''\\u0008>",
+"input":"<a a=''\u0008>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\u0008":""}]]},
+
+{"description":"<a a=''\\u0009>",
+"input":"<a a=''\u0009>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u000A>",
+"input":"<a a=''\u000A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u000B>",
+"input":"<a a=''\u000B>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\u000B":""}]]},
+
+{"description":"<a a=''\\u000C>",
+"input":"<a a=''\u000C>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u000D>",
+"input":"<a a=''\u000D>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u001F>",
+"input":"<a a=''\u001F>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\u001F":""}]]},
+
+{"description":"<a a='' >",
+"input":"<a a='' >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''!>",
+"input":"<a a=''!>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "!":""}]]},
+
+{"description":"<a a=''\">",
+"input":"<a a=''\">",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\"":""}]]},
+
+{"description":"<a a=''&>",
+"input":"<a a=''&>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "&":""}]]},
+
+{"description":"<a a='''>",
+"input":"<a a='''>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "'":""}]]},
+
+{"description":"<a a=''->",
+"input":"<a a=''->",
+"output":["ParseError", ["StartTag", "a", {"a":"", "-":""}]]},
+
+{"description":"<a a=''.>",
+"input":"<a a=''.>",
+"output":["ParseError", ["StartTag", "a", {"a":"", ".":""}]]},
+
+{"description":"<a a=''/>",
+"input":"<a a=''/>",
+"output":[["StartTag", "a", {"a":""}, true]]},
+
+{"description":"<a a=''0>",
+"input":"<a a=''0>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "0":""}]]},
+
+{"description":"<a a=''1>",
+"input":"<a a=''1>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "1":""}]]},
+
+{"description":"<a a=''9>",
+"input":"<a a=''9>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "9":""}]]},
+
+{"description":"<a a=''<>",
+"input":"<a a=''<>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "<":""}]]},
+
+{"description":"<a a=''=>",
+"input":"<a a=''=>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "=":""}]]},
+
+{"description":"<a a=''>",
+"input":"<a a=''>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''?>",
+"input":"<a a=''?>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "?":""}]]},
+
+{"description":"<a a=''@>",
+"input":"<a a=''@>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "@":""}]]},
+
+{"description":"<a a=''A>",
+"input":"<a a=''A>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''B>",
+"input":"<a a=''B>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a=''Y>",
+"input":"<a a=''Y>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a=''Z>",
+"input":"<a a=''Z>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a=''`>",
+"input":"<a a=''`>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "`":""}]]},
+
+{"description":"<a a=''a>",
+"input":"<a a=''a>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''b>",
+"input":"<a a=''b>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a=''y>",
+"input":"<a a=''y>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a=''z>",
+"input":"<a a=''z>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a=''{>",
+"input":"<a a=''{>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "{":""}]]},
+
+{"description":"<a a=''\\uDBC0\\uDC00>",
+"input":"<a a=''\uDBC0\uDC00>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\uDBC0\uDC00":""}]]},
+
+{"description":"<a a='('>",
+"input":"<a a='('>",
+"output":[["StartTag", "a", {"a":"("}]]},
+
+{"description":"<a a='-'>",
+"input":"<a a='-'>",
+"output":[["StartTag", "a", {"a":"-"}]]},
+
+{"description":"<a a='/'>",
+"input":"<a a='/'>",
+"output":[["StartTag", "a", {"a":"/"}]]},
+
+{"description":"<a a='0'>",
+"input":"<a a='0'>",
+"output":[["StartTag", "a", {"a":"0"}]]},
+
+{"description":"<a a='1'>",
+"input":"<a a='1'>",
+"output":[["StartTag", "a", {"a":"1"}]]},
+
+{"description":"<a a='9'>",
+"input":"<a a='9'>",
+"output":[["StartTag", "a", {"a":"9"}]]},
+
+{"description":"<a a='<'>",
+"input":"<a a='<'>",
+"output":[["StartTag", "a", {"a":"<"}]]},
+
+{"description":"<a a='='>",
+"input":"<a a='='>",
+"output":[["StartTag", "a", {"a":"="}]]},
+
+{"description":"<a a='>'>",
+"input":"<a a='>'>",
+"output":[["StartTag", "a", {"a":">"}]]},
+
+{"description":"<a a='?'>",
+"input":"<a a='?'>",
+"output":[["StartTag", "a", {"a":"?"}]]},
+
+{"description":"<a a='@'>",
+"input":"<a a='@'>",
+"output":[["StartTag", "a", {"a":"@"}]]},
+
+{"description":"<a a='A'>",
+"input":"<a a='A'>",
+"output":[["StartTag", "a", {"a":"A"}]]},
+
+{"description":"<a a='B'>",
+"input":"<a a='B'>",
+"output":[["StartTag", "a", {"a":"B"}]]},
+
+{"description":"<a a='Y'>",
+"input":"<a a='Y'>",
+"output":[["StartTag", "a", {"a":"Y"}]]},
+
+{"description":"<a a='Z'>",
+"input":"<a a='Z'>",
+"output":[["StartTag", "a", {"a":"Z"}]]},
+
+{"description":"<a a='`'>",
+"input":"<a a='`'>",
+"output":[["StartTag", "a", {"a":"`"}]]},
+
+{"description":"<a a='a'>",
+"input":"<a a='a'>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a='b'>",
+"input":"<a a='b'>",
+"output":[["StartTag", "a", {"a":"b"}]]},
+
+{"description":"<a a='y'>",
+"input":"<a a='y'>",
+"output":[["StartTag", "a", {"a":"y"}]]},
+
+{"description":"<a a='z'>",
+"input":"<a a='z'>",
+"output":[["StartTag", "a", {"a":"z"}]]},
+
+{"description":"<a a='{'>",
+"input":"<a a='{'>",
+"output":[["StartTag", "a", {"a":"{"}]]},
+
+{"description":"<a a='\\uDBC0\\uDC00'>",
+"input":"<a a='\uDBC0\uDC00'>",
+"output":[["StartTag", "a", {"a":"\uDBC0\uDC00"}]]},
+
+{"description":"<a a=(>",
+"input":"<a a=(>",
+"output":[["StartTag", "a", {"a":"("}]]},
+
+{"description":"<a a=->",
+"input":"<a a=->",
+"output":[["StartTag", "a", {"a":"-"}]]},
+
+{"description":"<a a=/>",
+"input":"<a a=/>",
+"output":[["StartTag", "a", {"a":"/"}]]},
+
+{"description":"<a a=0>",
+"input":"<a a=0>",
+"output":[["StartTag", "a", {"a":"0"}]]},
+
+{"description":"<a a=1>",
+"input":"<a a=1>",
+"output":[["StartTag", "a", {"a":"1"}]]},
+
+{"description":"<a a=9>",
+"input":"<a a=9>",
+"output":[["StartTag", "a", {"a":"9"}]]},
+
+{"description":"<a a=<>",
+"input":"<a a=<>",
+"output":["ParseError", ["StartTag", "a", {"a":"<"}]]},
+
+{"description":"<a a==>",
+"input":"<a a==>",
+"output":["ParseError", ["StartTag", "a", {"a":"="}]]},
+
+{"description":"<a a=>",
+"input":"<a a=>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=?>",
+"input":"<a a=?>",
+"output":[["StartTag", "a", {"a":"?"}]]},
+
+{"description":"<a a=@>",
+"input":"<a a=@>",
+"output":[["StartTag", "a", {"a":"@"}]]},
+
+{"description":"<a a=A>",
+"input":"<a a=A>",
+"output":[["StartTag", "a", {"a":"A"}]]},
+
+{"description":"<a a=B>",
+"input":"<a a=B>",
+"output":[["StartTag", "a", {"a":"B"}]]},
+
+{"description":"<a a=Y>",
+"input":"<a a=Y>",
+"output":[["StartTag", "a", {"a":"Y"}]]},
+
+{"description":"<a a=Z>",
+"input":"<a a=Z>",
+"output":[["StartTag", "a", {"a":"Z"}]]},
+
+{"description":"<a a=`>",
+"input":"<a a=`>",
+"output":["ParseError", ["StartTag", "a", {"a":"`"}]]},
+
+{"description":"<a a=a>",
+"input":"<a a=a>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u0000>",
+"input":"<a a=a\u0000>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\uFFFD"}]]},
+
+{"description":"<a a=a\\u0008>",
+"input":"<a a=a\u0008>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\u0008"}]]},
+
+{"description":"<a a=a\\u0009>",
+"input":"<a a=a\u0009>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u000A>",
+"input":"<a a=a\u000A>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u000B>",
+"input":"<a a=a\u000B>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\u000B"}]]},
+
+{"description":"<a a=a\\u000C>",
+"input":"<a a=a\u000C>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u000D>",
+"input":"<a a=a\u000D>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u001F>",
+"input":"<a a=a\u001F>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\u001F"}]]},
+
+{"description":"<a a=a >",
+"input":"<a a=a >",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a!>",
+"input":"<a a=a!>",
+"output":[["StartTag", "a", {"a":"a!"}]]},
+
+{"description":"<a a=a\">",
+"input":"<a a=a\">",
+"output":["ParseError", ["StartTag", "a", {"a":"a\""}]]},
+
+{"description":"<a a=a#>",
+"input":"<a a=a#>",
+"output":[["StartTag", "a", {"a":"a#"}]]},
+
+{"description":"<a a=a%>",
+"input":"<a a=a%>",
+"output":[["StartTag", "a", {"a":"a%"}]]},
+
+{"description":"<a a=a&>",
+"input":"<a a=a&>",
+"output":[["StartTag", "a", {"a":"a&"}]]},
+
+{"description":"<a a=a'>",
+"input":"<a a=a'>",
+"output":["ParseError", ["StartTag", "a", {"a":"a'"}]]},
+
+{"description":"<a a=a(>",
+"input":"<a a=a(>",
+"output":[["StartTag", "a", {"a":"a("}]]},
+
+{"description":"<a a=a->",
+"input":"<a a=a->",
+"output":[["StartTag", "a", {"a":"a-"}]]},
+
+{"description":"<a a=a/>",
+"input":"<a a=a/>",
+"output":[["StartTag", "a", {"a":"a/"}]]},
+
+{"description":"<a a=a0>",
+"input":"<a a=a0>",
+"output":[["StartTag", "a", {"a":"a0"}]]},
+
+{"description":"<a a=a1>",
+"input":"<a a=a1>",
+"output":[["StartTag", "a", {"a":"a1"}]]},
+
+{"description":"<a a=a9>",
+"input":"<a a=a9>",
+"output":[["StartTag", "a", {"a":"a9"}]]},
+
+{"description":"<a a=a<>",
+"input":"<a a=a<>",
+"output":["ParseError", ["StartTag", "a", {"a":"a<"}]]},
+
+{"description":"<a a=a=>",
+"input":"<a a=a=>",
+"output":["ParseError", ["StartTag", "a", {"a":"a="}]]},
+
+{"description":"<a a=a>",
+"input":"<a a=a>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a?>",
+"input":"<a a=a?>",
+"output":[["StartTag", "a", {"a":"a?"}]]},
+
+{"description":"<a a=a@>",
+"input":"<a a=a@>",
+"output":[["StartTag", "a", {"a":"a@"}]]},
+
+{"description":"<a a=aA>",
+"input":"<a a=aA>",
+"output":[["StartTag", "a", {"a":"aA"}]]},
+
+{"description":"<a a=aB>",
+"input":"<a a=aB>",
+"output":[["StartTag", "a", {"a":"aB"}]]},
+
+{"description":"<a a=aY>",
+"input":"<a a=aY>",
+"output":[["StartTag", "a", {"a":"aY"}]]},
+
+{"description":"<a a=aZ>",
+"input":"<a a=aZ>",
+"output":[["StartTag", "a", {"a":"aZ"}]]},
+
+{"description":"<a a=a`>",
+"input":"<a a=a`>",
+"output":["ParseError", ["StartTag", "a", {"a":"a`"}]]},
+
+{"description":"<a a=aa>",
+"input":"<a a=aa>",
+"output":[["StartTag", "a", {"a":"aa"}]]},
+
+{"description":"<a a=ab>",
+"input":"<a a=ab>",
+"output":[["StartTag", "a", {"a":"ab"}]]},
+
+{"description":"<a a=ay>",
+"input":"<a a=ay>",
+"output":[["StartTag", "a", {"a":"ay"}]]},
+
+{"description":"<a a=az>",
+"input":"<a a=az>",
+"output":[["StartTag", "a", {"a":"az"}]]},
+
+{"description":"<a a=a{>",
+"input":"<a a=a{>",
+"output":[["StartTag", "a", {"a":"a{"}]]},
+
+{"description":"<a a=a\\uDBC0\\uDC00>",
+"input":"<a a=a\uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a":"a\uDBC0\uDC00"}]]},
+
+{"description":"<a a=b>",
+"input":"<a a=b>",
+"output":[["StartTag", "a", {"a":"b"}]]},
+
+{"description":"<a a=y>",
+"input":"<a a=y>",
+"output":[["StartTag", "a", {"a":"y"}]]},
+
+{"description":"<a a=z>",
+"input":"<a a=z>",
+"output":[["StartTag", "a", {"a":"z"}]]},
+
+{"description":"<a a={>",
+"input":"<a a={>",
+"output":[["StartTag", "a", {"a":"{"}]]},
+
+{"description":"<a a=\\uDBC0\\uDC00>",
+"input":"<a a=\uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a":"\uDBC0\uDC00"}]]},
+
+{"description":"<a a>",
+"input":"<a a>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a?>",
+"input":"<a a?>",
+"output":[["StartTag", "a", {"a?":""}]]},
+
+{"description":"<a a@>",
+"input":"<a a@>",
+"output":[["StartTag", "a", {"a@":""}]]},
+
+{"description":"<a aA>",
+"input":"<a aA>",
+"output":[["StartTag", "a", {"aa":""}]]},
+
+{"description":"<a aB>",
+"input":"<a aB>",
+"output":[["StartTag", "a", {"ab":""}]]},
+
+{"description":"<a aY>",
+"input":"<a aY>",
+"output":[["StartTag", "a", {"ay":""}]]},
+
+{"description":"<a aZ>",
+"input":"<a aZ>",
+"output":[["StartTag", "a", {"az":""}]]},
+
+{"description":"<a a[>",
+"input":"<a a[>",
+"output":[["StartTag", "a", {"a[":""}]]},
+
+{"description":"<a a`>",
+"input":"<a a`>",
+"output":[["StartTag", "a", {"a`":""}]]},
+
+{"description":"<a aa>",
+"input":"<a aa>",
+"output":[["StartTag", "a", {"aa":""}]]},
+
+{"description":"<a ab>",
+"input":"<a ab>",
+"output":[["StartTag", "a", {"ab":""}]]},
+
+{"description":"<a ay>",
+"input":"<a ay>",
+"output":[["StartTag", "a", {"ay":""}]]},
+
+{"description":"<a az>",
+"input":"<a az>",
+"output":[["StartTag", "a", {"az":""}]]},
+
+{"description":"<a a{>",
+"input":"<a a{>",
+"output":[["StartTag", "a", {"a{":""}]]},
+
+{"description":"<a a\\uDBC0\\uDC00>",
+"input":"<a a\uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a\uDBC0\uDC00":""}]]},
+
+{"description":"<a b>",
+"input":"<a b>",
+"output":[["StartTag", "a", {"b":""}]]},
+
+{"description":"<a y>",
+"input":"<a y>",
+"output":[["StartTag", "a", {"y":""}]]},
+
+{"description":"<a z>",
+"input":"<a z>",
+"output":[["StartTag", "a", {"z":""}]]},
+
+{"description":"<a {>",
+"input":"<a {>",
+"output":[["StartTag", "a", {"{":""}]]},
+
+{"description":"<a \\uDBC0\\uDC00>",
+"input":"<a \uDBC0\uDC00>",
+"output":[["StartTag", "a", {"\uDBC0\uDC00":""}]]},
+
+{"description":"<a!>",
+"input":"<a!>",
+"output":[["StartTag", "a!", {}]]},
+
+{"description":"<a\">",
+"input":"<a\">",
+"output":[["StartTag", "a\"", {}]]},
+
+{"description":"<a&>",
+"input":"<a&>",
+"output":[["StartTag", "a&", {}]]},
+
+{"description":"<a'>",
+"input":"<a'>",
+"output":[["StartTag", "a'", {}]]},
+
+{"description":"<a->",
+"input":"<a->",
+"output":[["StartTag", "a-", {}]]},
+
+{"description":"<a.>",
+"input":"<a.>",
+"output":[["StartTag", "a.", {}]]},
+
+{"description":"<a/>",
+"input":"<a/>",
+"output":[["StartTag", "a", {}, true]]},
+
+{"description":"<a/\\u0000>",
+"input":"<a/\u0000>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"\uFFFD":""}]]},
+
+{"description":"<a/\\u0009>",
+"input":"<a/\u0009>",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/\\u000A>",
+"input":"<a/\u000A>",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/\\u000B>",
+"input":"<a/\u000B>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"\u000B":""}]]},
+
+{"description":"<a/\\u000C>",
+"input":"<a/\u000C>",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/ >",
+"input":"<a/ >",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/!>",
+"input":"<a/!>",
+"output":["ParseError", ["StartTag", "a", {"!":""}]]},
+
+{"description":"<a/\">",
+"input":"<a/\">",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"\"":""}]]},
+
+{"description":"<a/&>",
+"input":"<a/&>",
+"output":["ParseError", ["StartTag", "a", {"&":""}]]},
+
+{"description":"<a/'>",
+"input":"<a/'>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"'":""}]]},
+
+{"description":"<a/->",
+"input":"<a/->",
+"output":["ParseError", ["StartTag", "a", {"-":""}]]},
+
+{"description":"<a//>",
+"input":"<a//>",
+"output":["ParseError", ["StartTag", "a", {}, true]]},
+
+{"description":"<a/0>",
+"input":"<a/0>",
+"output":["ParseError", ["StartTag", "a", {"0":""}]]},
+
+{"description":"<a/1>",
+"input":"<a/1>",
+"output":["ParseError", ["StartTag", "a", {"1":""}]]},
+
+{"description":"<a/9>",
+"input":"<a/9>",
+"output":["ParseError", ["StartTag", "a", {"9":""}]]},
+
+{"description":"<a/<>",
+"input":"<a/<>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"<":""}]]},
+
+{"description":"<a/=>",
+"input":"<a/=>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"=":""}]]},
+
+{"description":"<a/>",
+"input":"<a/>",
+"output":[["StartTag", "a", {}, true]]},
+
+{"description":"<a/?>",
+"input":"<a/?>",
+"output":["ParseError", ["StartTag", "a", {"?":""}]]},
+
+{"description":"<a/@>",
+"input":"<a/@>",
+"output":["ParseError", ["StartTag", "a", {"@":""}]]},
+
+{"description":"<a/A>",
+"input":"<a/A>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a/B>",
+"input":"<a/B>",
+"output":["ParseError", ["StartTag", "a", {"b":""}]]},
+
+{"description":"<a/Y>",
+"input":"<a/Y>",
+"output":["ParseError", ["StartTag", "a", {"y":""}]]},
+
+{"description":"<a/Z>",
+"input":"<a/Z>",
+"output":["ParseError", ["StartTag", "a", {"z":""}]]},
+
+{"description":"<a/`>",
+"input":"<a/`>",
+"output":["ParseError", ["StartTag", "a", {"`":""}]]},
+
+{"description":"<a/a>",
+"input":"<a/a>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a/b>",
+"input":"<a/b>",
+"output":["ParseError", ["StartTag", "a", {"b":""}]]},
+
+{"description":"<a/y>",
+"input":"<a/y>",
+"output":["ParseError", ["StartTag", "a", {"y":""}]]},
+
+{"description":"<a/z>",
+"input":"<a/z>",
+"output":["ParseError", ["StartTag", "a", {"z":""}]]},
+
+{"description":"<a/{>",
+"input":"<a/{>",
+"output":["ParseError", ["StartTag", "a", {"{":""}]]},
+
+{"description":"<a/\\uDBC0\\uDC00>",
+"input":"<a/\uDBC0\uDC00>",
+"output":["ParseError", ["StartTag", "a", {"\uDBC0\uDC00":""}]]},
+
+{"description":"<a0>",
+"input":"<a0>",
+"output":[["StartTag", "a0", {}]]},
+
+{"description":"<a1>",
+"input":"<a1>",
+"output":[["StartTag", "a1", {}]]},
+
+{"description":"<a9>",
+"input":"<a9>",
+"output":[["StartTag", "a9", {}]]},
+
+{"description":"<a<>",
+"input":"<a<>",
+"output":[["StartTag", "a<", {}]]},
+
+{"description":"<a=>",
+"input":"<a=>",
+"output":[["StartTag", "a=", {}]]},
+
+{"description":"<a>",
+"input":"<a>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a?>",
+"input":"<a?>",
+"output":[["StartTag", "a?", {}]]},
+
+{"description":"<a@>",
+"input":"<a@>",
+"output":[["StartTag", "a@", {}]]},
+
+{"description":"<aA>",
+"input":"<aA>",
+"output":[["StartTag", "aa", {}]]},
+
+{"description":"<aB>",
+"input":"<aB>",
+"output":[["StartTag", "ab", {}]]},
+
+{"description":"<aY>",
+"input":"<aY>",
+"output":[["StartTag", "ay", {}]]},
+
+{"description":"<aZ>",
+"input":"<aZ>",
+"output":[["StartTag", "az", {}]]},
+
+{"description":"<a[>",
+"input":"<a[>",
+"output":[["StartTag", "a[", {}]]},
+
+{"description":"<a`>",
+"input":"<a`>",
+"output":[["StartTag", "a`", {}]]},
+
+{"description":"<aa>",
+"input":"<aa>",
+"output":[["StartTag", "aa", {}]]},
+
+{"description":"<ab>",
+"input":"<ab>",
+"output":[["StartTag", "ab", {}]]},
+
+{"description":"<ay>",
+"input":"<ay>",
+"output":[["StartTag", "ay", {}]]},
+
+{"description":"<az>",
+"input":"<az>",
+"output":[["StartTag", "az", {}]]},
+
+{"description":"<a{>",
+"input":"<a{>",
+"output":[["StartTag", "a{", {}]]},
+
+{"description":"<a\\uDBC0\\uDC00>",
+"input":"<a\uDBC0\uDC00>",
+"output":[["StartTag", "a\uDBC0\uDC00", {}]]},
+
+{"description":"<b>",
+"input":"<b>",
+"output":[["StartTag", "b", {}]]},
+
+{"description":"<y>",
+"input":"<y>",
+"output":[["StartTag", "y", {}]]},
+
+{"description":"<z>",
+"input":"<z>",
+"output":[["StartTag", "z", {}]]},
+
+{"description":"<{",
+"input":"<{",
+"output":["ParseError", ["Character", "<{"]]},
+
+{"description":"<\\uDBC0\\uDC00",
+"input":"<\uDBC0\uDC00",
+"output":["ParseError", ["Character", "<\uDBC0\uDC00"]]},
+
+{"description":"=",
+"input":"=",
+"output":[["Character", "="]]},
+
+{"description":">",
+"input":">",
+"output":[["Character", ">"]]},
+
+{"description":"?",
+"input":"?",
+"output":[["Character", "?"]]},
+
+{"description":"@",
+"input":"@",
+"output":[["Character", "@"]]},
+
+{"description":"A",
+"input":"A",
+"output":[["Character", "A"]]},
+
+{"description":"B",
+"input":"B",
+"output":[["Character", "B"]]},
+
+{"description":"Y",
+"input":"Y",
+"output":[["Character", "Y"]]},
+
+{"description":"Z",
+"input":"Z",
+"output":[["Character", "Z"]]},
+
+{"description":"`",
+"input":"`",
+"output":[["Character", "`"]]},
+
+{"description":"a",
+"input":"a",
+"output":[["Character", "a"]]},
+
+{"description":"b",
+"input":"b",
+"output":[["Character", "b"]]},
+
+{"description":"y",
+"input":"y",
+"output":[["Character", "y"]]},
+
+{"description":"z",
+"input":"z",
+"output":[["Character", "z"]]},
+
+{"description":"{",
+"input":"{",
+"output":[["Character", "{"]]},
+
+{"description":"\\uDBC0\\uDC00",
+"input":"\uDBC0\uDC00",
+"output":[["Character", "\uDBC0\uDC00"]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/test4.test b/pkg/third_party/html5lib/test/data/tokenizer/test4.test
new file mode 100644
index 0000000..80f859e2
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/test4.test
@@ -0,0 +1,344 @@
+{"tests": [
+
+{"description":"< in attribute name",
+"input":"<z/0  <>",
+"output":["ParseError", "ParseError", ["StartTag", "z", {"0": "", "<": ""}]]},
+
+{"description":"< in attribute value",
+"input":"<z x=<>",
+"output":["ParseError", ["StartTag", "z", {"x": "<"}]]},
+
+{"description":"= in unquoted attribute value",
+"input":"<z z=z=z>",
+"output":["ParseError", ["StartTag", "z", {"z": "z=z"}]]},
+
+{"description":"= attribute",
+"input":"<z =>",
+"output":["ParseError", ["StartTag", "z", {"=": ""}]]},
+
+{"description":"== attribute",
+"input":"<z ==>",
+"output":["ParseError", "ParseError", ["StartTag", "z", {"=": ""}]]},
+
+{"description":"=== attribute",
+"input":"<z ===>",
+"output":["ParseError", "ParseError", ["StartTag", "z", {"=": "="}]]},
+
+{"description":"==== attribute",
+"input":"<z ====>",
+"output":["ParseError", "ParseError", "ParseError", ["StartTag", "z", {"=": "=="}]]},
+
+{"description":"Allowed \" after ampersand in attribute value",
+"input":"<z z=\"&\">",
+"output":[["StartTag", "z", {"z": "&"}]]},
+
+{"description":"Non-allowed ' after ampersand in attribute value",
+"input":"<z z=\"&'\">",
+"output":["ParseError", ["StartTag", "z", {"z": "&'"}]]},
+
+{"description":"Allowed ' after ampersand in attribute value",
+"input":"<z z='&'>",
+"output":[["StartTag", "z", {"z": "&"}]]},
+
+{"description":"Non-allowed \" after ampersand in attribute value",
+"input":"<z z='&\"'>",
+"output":["ParseError", ["StartTag", "z", {"z": "&\""}]]},
+
+{"description":"Text after bogus character reference",
+"input":"<z z='&xlink_xmlns;'>bar<z>",
+"output":["ParseError",["StartTag","z",{"z":"&xlink_xmlns;"}],["Character","bar"],["StartTag","z",{}]]},
+
+{"description":"Text after hex character reference",
+"input":"<z z='&#x0020; foo'>bar<z>",
+"output":[["StartTag","z",{"z":"  foo"}],["Character","bar"],["StartTag","z",{}]]},
+
+{"description":"Attribute name starting with \"",
+"input":"<foo \"='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"\"": "bar"}]]},
+
+{"description":"Attribute name starting with '",
+"input":"<foo '='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"'": "bar"}]]},
+
+{"description":"Attribute name containing \"",
+"input":"<foo a\"b='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"a\"b": "bar"}]]},
+
+{"description":"Attribute name containing '",
+"input":"<foo a'b='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"a'b": "bar"}]]},
+
+{"description":"Unquoted attribute value containing '",
+"input":"<foo a=b'c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b'c"}]]},
+
+{"description":"Unquoted attribute value containing \"",
+"input":"<foo a=b\"c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b\"c"}]]},
+
+{"description":"Double-quoted attribute value not followed by whitespace",
+"input":"<foo a=\"b\"c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b", "c": ""}]]},
+
+{"description":"Single-quoted attribute value not followed by whitespace",
+"input":"<foo a='b'c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b", "c": ""}]]},
+
+{"description":"Quoted attribute followed by permitted /",
+"input":"<br a='b'/>",
+"output":[["StartTag","br",{"a":"b"},true]]},
+
+{"description":"Quoted attribute followed by non-permitted /",
+"input":"<bar a='b'/>",
+"output":[["StartTag","bar",{"a":"b"},true]]},
+
+{"description":"CR EOF after doctype name",
+"input":"<!doctype html \r",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"CR EOF in tag name",
+"input":"<z\r",
+"output":["ParseError"]},
+
+{"description":"Slash EOF in tag name",
+"input":"<z/",
+"output":["ParseError"]},
+
+{"description":"Zero hex numeric entity",
+"input":"&#x0",
+"output":["ParseError", "ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Zero decimal numeric entity",
+"input":"&#0",
+"output":["ParseError", "ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Zero-prefixed hex numeric entity",
+"input":"&#x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041;",
+"output":[["Character", "A"]]},
+
+{"description":"Zero-prefixed decimal numeric entity",
+"input":"&#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065;",
+"output":[["Character", "A"]]},
+
+{"description":"Empty hex numeric entities",
+"input":"&#x &#X ",
+"output":["ParseError", ["Character", "&#x "], "ParseError", ["Character", "&#X "]]},
+
+{"description":"Empty decimal numeric entities",
+"input":"&# &#; ",
+"output":["ParseError", ["Character", "&# "], "ParseError", ["Character", "&#; "]]},
+
+{"description":"Non-BMP numeric entity",
+"input":"&#x10000;",
+"output":[["Character", "\uD800\uDC00"]]},
+
+{"description":"Maximum non-BMP numeric entity",
+"input":"&#X10FFFF;",
+"output":["ParseError", ["Character", "\uDBFF\uDFFF"]]},
+
+{"description":"Above maximum numeric entity",
+"input":"&#x110000;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"32-bit hex numeric entity",
+"input":"&#x80000041;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"33-bit hex numeric entity",
+"input":"&#x100000041;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"33-bit decimal numeric entity",
+"input":"&#4294967361;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"65-bit hex numeric entity",
+"input":"&#x10000000000000041;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"65-bit decimal numeric entity",
+"input":"&#18446744073709551681;",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Surrogate code point edge cases",
+"input":"&#xD7FF;&#xD800;&#xD801;&#xDFFE;&#xDFFF;&#xE000;",
+"output":[["Character", "\uD7FF"], "ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD\uE000"]]},
+
+{"description":"Uppercase start tag name",
+"input":"<X>",
+"output":[["StartTag", "x", {}]]},
+
+{"description":"Uppercase end tag name",
+"input":"</X>",
+"output":[["EndTag", "x"]]},
+
+{"description":"Uppercase attribute name",
+"input":"<x X>",
+"output":[["StartTag", "x", { "x":"" }]]},
+
+{"description":"Tag/attribute name case edge values",
+"input":"<x@AZ[`az{ @AZ[`az{>",
+"output":[["StartTag", "x@az[`az{", { "@az[`az{":"" }]]},
+
+{"description":"Duplicate different-case attributes",
+"input":"<x x=1 x=2 X=3>",
+"output":["ParseError", "ParseError", ["StartTag", "x", { "x":"1" }]]},
+
+{"description":"Uppercase close tag attributes",
+"input":"</x X>",
+"output":["ParseError", ["EndTag", "x"]]},
+
+{"description":"Duplicate close tag attributes",
+"input":"</x x x>",
+"output":["ParseError", "ParseError", ["EndTag", "x"]]},
+
+{"description":"Permitted slash",
+"input":"<br/>",
+"output":[["StartTag","br",{},true]]},
+
+{"description":"Non-permitted slash",
+"input":"<xr/>",
+"output":[["StartTag","xr",{},true]]},
+
+{"description":"Permitted slash but in close tag",
+"input":"</br/>",
+"output":["ParseError", ["EndTag", "br"]]},
+
+{"description":"Doctype public case-sensitivity (1)",
+"input":"<!DoCtYpE HtMl PuBlIc \"AbC\" \"XyZ\">",
+"output":[["DOCTYPE", "html", "AbC", "XyZ", true]]},
+
+{"description":"Doctype public case-sensitivity (2)",
+"input":"<!dOcTyPe hTmL pUbLiC \"aBc\" \"xYz\">",
+"output":[["DOCTYPE", "html", "aBc", "xYz", true]]},
+
+{"description":"Doctype system case-sensitivity (1)",
+"input":"<!DoCtYpE HtMl SyStEm \"XyZ\">",
+"output":[["DOCTYPE", "html", null, "XyZ", true]]},
+
+{"description":"Doctype system case-sensitivity (2)",
+"input":"<!dOcTyPe hTmL sYsTeM \"xYz\">",
+"output":[["DOCTYPE", "html", null, "xYz", true]]},
+
+{"description":"U+0000 in lookahead region after non-matching character",
+"input":"<!doc>\u0000",
+"output":["ParseError", ["Comment", "doc"], "ParseError", ["Character", "\u0000"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+0000 in lookahead region",
+"input":"<!doc\u0000",
+"output":["ParseError", ["Comment", "doc\uFFFD"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+0080 in lookahead region",
+"input":"<!doc\u0080",
+"output":["ParseError", "ParseError", ["Comment", "doc\u0080"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+FDD1 in lookahead region",
+"input":"<!doc\uFDD1",
+"output":["ParseError", "ParseError", ["Comment", "doc\uFDD1"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+1FFFF in lookahead region",
+"input":"<!doc\uD83F\uDFFF",
+"output":["ParseError", "ParseError", ["Comment", "doc\uD83F\uDFFF"]],
+"ignoreErrorOrder":true},
+
+{"description":"CR followed by non-LF",
+"input":"\r?",
+"output":[["Character", "\n?"]]},
+
+{"description":"CR at EOF",
+"input":"\r",
+"output":[["Character", "\n"]]},
+
+{"description":"LF at EOF",
+"input":"\n",
+"output":[["Character", "\n"]]},
+
+{"description":"CR LF",
+"input":"\r\n",
+"output":[["Character", "\n"]]},
+
+{"description":"CR CR",
+"input":"\r\r",
+"output":[["Character", "\n\n"]]},
+
+{"description":"LF LF",
+"input":"\n\n",
+"output":[["Character", "\n\n"]]},
+
+{"description":"LF CR",
+"input":"\n\r",
+"output":[["Character", "\n\n"]]},
+
+{"description":"text CR CR CR text",
+"input":"text\r\r\rtext",
+"output":[["Character", "text\n\n\ntext"]]},
+
+{"description":"Doctype publik",
+"input":"<!DOCTYPE html PUBLIK \"AbC\" \"XyZ\">",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype publi",
+"input":"<!DOCTYPE html PUBLI",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype sistem",
+"input":"<!DOCTYPE html SISTEM \"AbC\">",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype sys",
+"input":"<!DOCTYPE html SYS",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype html x>text",
+"input":"<!DOCTYPE html x>text",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false], ["Character", "text"]]},
+
+{"description":"Grave accent in unquoted attribute",
+"input":"<a a=aa`>",
+"output":["ParseError", ["StartTag", "a", {"a":"aa`"}]]},
+
+{"description":"EOF in tag name state ",
+"input":"<a",
+"output":["ParseError"]},
+
+{"description":"EOF in tag name state",
+"input":"<a",
+"output":["ParseError"]},
+
+{"description":"EOF in before attribute name state",
+"input":"<a ",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute name state",
+"input":"<a a",
+"output":["ParseError"]},
+
+{"description":"EOF in after attribute name state",
+"input":"<a a ",
+"output":["ParseError"]},
+
+{"description":"EOF in before attribute value state",
+"input":"<a a =",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute value (double quoted) state",
+"input":"<a a =\"a",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute value (single quoted) state",
+"input":"<a a ='a",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute value (unquoted) state",
+"input":"<a a =a",
+"output":["ParseError"]},
+
+{"description":"EOF in after attribute value state",
+"input":"<a a ='a'",
+"output":["ParseError"]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/unicodeChars.test b/pkg/third_party/html5lib/test/data/tokenizer/unicodeChars.test
new file mode 100644
index 0000000..c778668
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/unicodeChars.test
@@ -0,0 +1,1295 @@
+{"tests": [
+
+{"description": "Invalid Unicode character U+0001",
+"input": "\u0001",
+"output": ["ParseError", ["Character", "\u0001"]]},
+
+{"description": "Invalid Unicode character U+0002",
+"input": "\u0002",
+"output": ["ParseError", ["Character", "\u0002"]]},
+
+{"description": "Invalid Unicode character U+0003",
+"input": "\u0003",
+"output": ["ParseError", ["Character", "\u0003"]]},
+
+{"description": "Invalid Unicode character U+0004",
+"input": "\u0004",
+"output": ["ParseError", ["Character", "\u0004"]]},
+
+{"description": "Invalid Unicode character U+0005",
+"input": "\u0005",
+"output": ["ParseError", ["Character", "\u0005"]]},
+
+{"description": "Invalid Unicode character U+0006",
+"input": "\u0006",
+"output": ["ParseError", ["Character", "\u0006"]]},
+
+{"description": "Invalid Unicode character U+0007",
+"input": "\u0007",
+"output": ["ParseError", ["Character", "\u0007"]]},
+
+{"description": "Invalid Unicode character U+0008",
+"input": "\u0008",
+"output": ["ParseError", ["Character", "\u0008"]]},
+
+{"description": "Invalid Unicode character U+000B",
+"input": "\u000B",
+"output": ["ParseError", ["Character", "\u000B"]]},
+
+{"description": "Invalid Unicode character U+000E",
+"input": "\u000E",
+"output": ["ParseError", ["Character", "\u000E"]]},
+
+{"description": "Invalid Unicode character U+000F",
+"input": "\u000F",
+"output": ["ParseError", ["Character", "\u000F"]]},
+
+{"description": "Invalid Unicode character U+0010",
+"input": "\u0010",
+"output": ["ParseError", ["Character", "\u0010"]]},
+
+{"description": "Invalid Unicode character U+0011",
+"input": "\u0011",
+"output": ["ParseError", ["Character", "\u0011"]]},
+
+{"description": "Invalid Unicode character U+0012",
+"input": "\u0012",
+"output": ["ParseError", ["Character", "\u0012"]]},
+
+{"description": "Invalid Unicode character U+0013",
+"input": "\u0013",
+"output": ["ParseError", ["Character", "\u0013"]]},
+
+{"description": "Invalid Unicode character U+0014",
+"input": "\u0014",
+"output": ["ParseError", ["Character", "\u0014"]]},
+
+{"description": "Invalid Unicode character U+0015",
+"input": "\u0015",
+"output": ["ParseError", ["Character", "\u0015"]]},
+
+{"description": "Invalid Unicode character U+0016",
+"input": "\u0016",
+"output": ["ParseError", ["Character", "\u0016"]]},
+
+{"description": "Invalid Unicode character U+0017",
+"input": "\u0017",
+"output": ["ParseError", ["Character", "\u0017"]]},
+
+{"description": "Invalid Unicode character U+0018",
+"input": "\u0018",
+"output": ["ParseError", ["Character", "\u0018"]]},
+
+{"description": "Invalid Unicode character U+0019",
+"input": "\u0019",
+"output": ["ParseError", ["Character", "\u0019"]]},
+
+{"description": "Invalid Unicode character U+001A",
+"input": "\u001A",
+"output": ["ParseError", ["Character", "\u001A"]]},
+
+{"description": "Invalid Unicode character U+001B",
+"input": "\u001B",
+"output": ["ParseError", ["Character", "\u001B"]]},
+
+{"description": "Invalid Unicode character U+001C",
+"input": "\u001C",
+"output": ["ParseError", ["Character", "\u001C"]]},
+
+{"description": "Invalid Unicode character U+001D",
+"input": "\u001D",
+"output": ["ParseError", ["Character", "\u001D"]]},
+
+{"description": "Invalid Unicode character U+001E",
+"input": "\u001E",
+"output": ["ParseError", ["Character", "\u001E"]]},
+
+{"description": "Invalid Unicode character U+001F",
+"input": "\u001F",
+"output": ["ParseError", ["Character", "\u001F"]]},
+
+{"description": "Invalid Unicode character U+007F",
+"input": "\u007F",
+"output": ["ParseError", ["Character", "\u007F"]]},
+
+{"description": "Invalid Unicode character U+FDD0",
+"input": "\uFDD0",
+"output": ["ParseError", ["Character", "\uFDD0"]]},
+
+{"description": "Invalid Unicode character U+FDD1",
+"input": "\uFDD1",
+"output": ["ParseError", ["Character", "\uFDD1"]]},
+
+{"description": "Invalid Unicode character U+FDD2",
+"input": "\uFDD2",
+"output": ["ParseError", ["Character", "\uFDD2"]]},
+
+{"description": "Invalid Unicode character U+FDD3",
+"input": "\uFDD3",
+"output": ["ParseError", ["Character", "\uFDD3"]]},
+
+{"description": "Invalid Unicode character U+FDD4",
+"input": "\uFDD4",
+"output": ["ParseError", ["Character", "\uFDD4"]]},
+
+{"description": "Invalid Unicode character U+FDD5",
+"input": "\uFDD5",
+"output": ["ParseError", ["Character", "\uFDD5"]]},
+
+{"description": "Invalid Unicode character U+FDD6",
+"input": "\uFDD6",
+"output": ["ParseError", ["Character", "\uFDD6"]]},
+
+{"description": "Invalid Unicode character U+FDD7",
+"input": "\uFDD7",
+"output": ["ParseError", ["Character", "\uFDD7"]]},
+
+{"description": "Invalid Unicode character U+FDD8",
+"input": "\uFDD8",
+"output": ["ParseError", ["Character", "\uFDD8"]]},
+
+{"description": "Invalid Unicode character U+FDD9",
+"input": "\uFDD9",
+"output": ["ParseError", ["Character", "\uFDD9"]]},
+
+{"description": "Invalid Unicode character U+FDDA",
+"input": "\uFDDA",
+"output": ["ParseError", ["Character", "\uFDDA"]]},
+
+{"description": "Invalid Unicode character U+FDDB",
+"input": "\uFDDB",
+"output": ["ParseError", ["Character", "\uFDDB"]]},
+
+{"description": "Invalid Unicode character U+FDDC",
+"input": "\uFDDC",
+"output": ["ParseError", ["Character", "\uFDDC"]]},
+
+{"description": "Invalid Unicode character U+FDDD",
+"input": "\uFDDD",
+"output": ["ParseError", ["Character", "\uFDDD"]]},
+
+{"description": "Invalid Unicode character U+FDDE",
+"input": "\uFDDE",
+"output": ["ParseError", ["Character", "\uFDDE"]]},
+
+{"description": "Invalid Unicode character U+FDDF",
+"input": "\uFDDF",
+"output": ["ParseError", ["Character", "\uFDDF"]]},
+
+{"description": "Invalid Unicode character U+FDE0",
+"input": "\uFDE0",
+"output": ["ParseError", ["Character", "\uFDE0"]]},
+
+{"description": "Invalid Unicode character U+FDE1",
+"input": "\uFDE1",
+"output": ["ParseError", ["Character", "\uFDE1"]]},
+
+{"description": "Invalid Unicode character U+FDE2",
+"input": "\uFDE2",
+"output": ["ParseError", ["Character", "\uFDE2"]]},
+
+{"description": "Invalid Unicode character U+FDE3",
+"input": "\uFDE3",
+"output": ["ParseError", ["Character", "\uFDE3"]]},
+
+{"description": "Invalid Unicode character U+FDE4",
+"input": "\uFDE4",
+"output": ["ParseError", ["Character", "\uFDE4"]]},
+
+{"description": "Invalid Unicode character U+FDE5",
+"input": "\uFDE5",
+"output": ["ParseError", ["Character", "\uFDE5"]]},
+
+{"description": "Invalid Unicode character U+FDE6",
+"input": "\uFDE6",
+"output": ["ParseError", ["Character", "\uFDE6"]]},
+
+{"description": "Invalid Unicode character U+FDE7",
+"input": "\uFDE7",
+"output": ["ParseError", ["Character", "\uFDE7"]]},
+
+{"description": "Invalid Unicode character U+FDE8",
+"input": "\uFDE8",
+"output": ["ParseError", ["Character", "\uFDE8"]]},
+
+{"description": "Invalid Unicode character U+FDE9",
+"input": "\uFDE9",
+"output": ["ParseError", ["Character", "\uFDE9"]]},
+
+{"description": "Invalid Unicode character U+FDEA",
+"input": "\uFDEA",
+"output": ["ParseError", ["Character", "\uFDEA"]]},
+
+{"description": "Invalid Unicode character U+FDEB",
+"input": "\uFDEB",
+"output": ["ParseError", ["Character", "\uFDEB"]]},
+
+{"description": "Invalid Unicode character U+FDEC",
+"input": "\uFDEC",
+"output": ["ParseError", ["Character", "\uFDEC"]]},
+
+{"description": "Invalid Unicode character U+FDED",
+"input": "\uFDED",
+"output": ["ParseError", ["Character", "\uFDED"]]},
+
+{"description": "Invalid Unicode character U+FDEE",
+"input": "\uFDEE",
+"output": ["ParseError", ["Character", "\uFDEE"]]},
+
+{"description": "Invalid Unicode character U+FDEF",
+"input": "\uFDEF",
+"output": ["ParseError", ["Character", "\uFDEF"]]},
+
+{"description": "Invalid Unicode character U+FFFE",
+"input": "\uFFFE",
+"output": ["ParseError", ["Character", "\uFFFE"]]},
+
+{"description": "Invalid Unicode character U+FFFF",
+"input": "\uFFFF",
+"output": ["ParseError", ["Character", "\uFFFF"]]},
+
+{"description": "Invalid Unicode character U+1FFFE",
+"input": "\uD83F\uDFFE",
+"output": ["ParseError", ["Character", "\uD83F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+1FFFF",
+"input": "\uD83F\uDFFF",
+"output": ["ParseError", ["Character", "\uD83F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+2FFFE",
+"input": "\uD87F\uDFFE",
+"output": ["ParseError", ["Character", "\uD87F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+2FFFF",
+"input": "\uD87F\uDFFF",
+"output": ["ParseError", ["Character", "\uD87F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+3FFFE",
+"input": "\uD8BF\uDFFE",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+3FFFF",
+"input": "\uD8BF\uDFFF",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+4FFFE",
+"input": "\uD8FF\uDFFE",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+4FFFF",
+"input": "\uD8FF\uDFFF",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+5FFFE",
+"input": "\uD93F\uDFFE",
+"output": ["ParseError", ["Character", "\uD93F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+5FFFF",
+"input": "\uD93F\uDFFF",
+"output": ["ParseError", ["Character", "\uD93F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+6FFFE",
+"input": "\uD97F\uDFFE",
+"output": ["ParseError", ["Character", "\uD97F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+6FFFF",
+"input": "\uD97F\uDFFF",
+"output": ["ParseError", ["Character", "\uD97F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+7FFFE",
+"input": "\uD9BF\uDFFE",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+7FFFF",
+"input": "\uD9BF\uDFFF",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+8FFFE",
+"input": "\uD9FF\uDFFE",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+8FFFF",
+"input": "\uD9FF\uDFFF",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+9FFFE",
+"input": "\uDA3F\uDFFE",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+9FFFF",
+"input": "\uDA3F\uDFFF",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+AFFFE",
+"input": "\uDA7F\uDFFE",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+AFFFF",
+"input": "\uDA7F\uDFFF",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+BFFFE",
+"input": "\uDABF\uDFFE",
+"output": ["ParseError", ["Character", "\uDABF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+BFFFF",
+"input": "\uDABF\uDFFF",
+"output": ["ParseError", ["Character", "\uDABF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+CFFFE",
+"input": "\uDAFF\uDFFE",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+CFFFF",
+"input": "\uDAFF\uDFFF",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+DFFFE",
+"input": "\uDB3F\uDFFE",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+DFFFF",
+"input": "\uDB3F\uDFFF",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+EFFFE",
+"input": "\uDB7F\uDFFE",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+EFFFF",
+"input": "\uDB7F\uDFFF",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+FFFFE",
+"input": "\uDBBF\uDFFE",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+FFFFF",
+"input": "\uDBBF\uDFFF",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+10FFFE",
+"input": "\uDBFF\uDFFE",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+10FFFF",
+"input": "\uDBFF\uDFFF",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFF"]]},
+
+{"description": "Valid Unicode character U+0009",
+"input": "\u0009",
+"output": [["Character", "\u0009"]]},
+
+{"description": "Valid Unicode character U+000A",
+"input": "\u000A",
+"output": [["Character", "\u000A"]]},
+
+{"description": "Valid Unicode character U+0020",
+"input": "\u0020",
+"output": [["Character", "\u0020"]]},
+
+{"description": "Valid Unicode character U+0021",
+"input": "\u0021",
+"output": [["Character", "\u0021"]]},
+
+{"description": "Valid Unicode character U+0022",
+"input": "\u0022",
+"output": [["Character", "\u0022"]]},
+
+{"description": "Valid Unicode character U+0023",
+"input": "\u0023",
+"output": [["Character", "\u0023"]]},
+
+{"description": "Valid Unicode character U+0024",
+"input": "\u0024",
+"output": [["Character", "\u0024"]]},
+
+{"description": "Valid Unicode character U+0025",
+"input": "\u0025",
+"output": [["Character", "\u0025"]]},
+
+{"description": "Valid Unicode character U+0026",
+"input": "\u0026",
+"output": [["Character", "\u0026"]]},
+
+{"description": "Valid Unicode character U+0027",
+"input": "\u0027",
+"output": [["Character", "\u0027"]]},
+
+{"description": "Valid Unicode character U+0028",
+"input": "\u0028",
+"output": [["Character", "\u0028"]]},
+
+{"description": "Valid Unicode character U+0029",
+"input": "\u0029",
+"output": [["Character", "\u0029"]]},
+
+{"description": "Valid Unicode character U+002A",
+"input": "\u002A",
+"output": [["Character", "\u002A"]]},
+
+{"description": "Valid Unicode character U+002B",
+"input": "\u002B",
+"output": [["Character", "\u002B"]]},
+
+{"description": "Valid Unicode character U+002C",
+"input": "\u002C",
+"output": [["Character", "\u002C"]]},
+
+{"description": "Valid Unicode character U+002D",
+"input": "\u002D",
+"output": [["Character", "\u002D"]]},
+
+{"description": "Valid Unicode character U+002E",
+"input": "\u002E",
+"output": [["Character", "\u002E"]]},
+
+{"description": "Valid Unicode character U+002F",
+"input": "\u002F",
+"output": [["Character", "\u002F"]]},
+
+{"description": "Valid Unicode character U+0030",
+"input": "\u0030",
+"output": [["Character", "\u0030"]]},
+
+{"description": "Valid Unicode character U+0031",
+"input": "\u0031",
+"output": [["Character", "\u0031"]]},
+
+{"description": "Valid Unicode character U+0032",
+"input": "\u0032",
+"output": [["Character", "\u0032"]]},
+
+{"description": "Valid Unicode character U+0033",
+"input": "\u0033",
+"output": [["Character", "\u0033"]]},
+
+{"description": "Valid Unicode character U+0034",
+"input": "\u0034",
+"output": [["Character", "\u0034"]]},
+
+{"description": "Valid Unicode character U+0035",
+"input": "\u0035",
+"output": [["Character", "\u0035"]]},
+
+{"description": "Valid Unicode character U+0036",
+"input": "\u0036",
+"output": [["Character", "\u0036"]]},
+
+{"description": "Valid Unicode character U+0037",
+"input": "\u0037",
+"output": [["Character", "\u0037"]]},
+
+{"description": "Valid Unicode character U+0038",
+"input": "\u0038",
+"output": [["Character", "\u0038"]]},
+
+{"description": "Valid Unicode character U+0039",
+"input": "\u0039",
+"output": [["Character", "\u0039"]]},
+
+{"description": "Valid Unicode character U+003A",
+"input": "\u003A",
+"output": [["Character", "\u003A"]]},
+
+{"description": "Valid Unicode character U+003B",
+"input": "\u003B",
+"output": [["Character", "\u003B"]]},
+
+{"description": "Valid Unicode character U+003D",
+"input": "\u003D",
+"output": [["Character", "\u003D"]]},
+
+{"description": "Valid Unicode character U+003E",
+"input": "\u003E",
+"output": [["Character", "\u003E"]]},
+
+{"description": "Valid Unicode character U+003F",
+"input": "\u003F",
+"output": [["Character", "\u003F"]]},
+
+{"description": "Valid Unicode character U+0040",
+"input": "\u0040",
+"output": [["Character", "\u0040"]]},
+
+{"description": "Valid Unicode character U+0041",
+"input": "\u0041",
+"output": [["Character", "\u0041"]]},
+
+{"description": "Valid Unicode character U+0042",
+"input": "\u0042",
+"output": [["Character", "\u0042"]]},
+
+{"description": "Valid Unicode character U+0043",
+"input": "\u0043",
+"output": [["Character", "\u0043"]]},
+
+{"description": "Valid Unicode character U+0044",
+"input": "\u0044",
+"output": [["Character", "\u0044"]]},
+
+{"description": "Valid Unicode character U+0045",
+"input": "\u0045",
+"output": [["Character", "\u0045"]]},
+
+{"description": "Valid Unicode character U+0046",
+"input": "\u0046",
+"output": [["Character", "\u0046"]]},
+
+{"description": "Valid Unicode character U+0047",
+"input": "\u0047",
+"output": [["Character", "\u0047"]]},
+
+{"description": "Valid Unicode character U+0048",
+"input": "\u0048",
+"output": [["Character", "\u0048"]]},
+
+{"description": "Valid Unicode character U+0049",
+"input": "\u0049",
+"output": [["Character", "\u0049"]]},
+
+{"description": "Valid Unicode character U+004A",
+"input": "\u004A",
+"output": [["Character", "\u004A"]]},
+
+{"description": "Valid Unicode character U+004B",
+"input": "\u004B",
+"output": [["Character", "\u004B"]]},
+
+{"description": "Valid Unicode character U+004C",
+"input": "\u004C",
+"output": [["Character", "\u004C"]]},
+
+{"description": "Valid Unicode character U+004D",
+"input": "\u004D",
+"output": [["Character", "\u004D"]]},
+
+{"description": "Valid Unicode character U+004E",
+"input": "\u004E",
+"output": [["Character", "\u004E"]]},
+
+{"description": "Valid Unicode character U+004F",
+"input": "\u004F",
+"output": [["Character", "\u004F"]]},
+
+{"description": "Valid Unicode character U+0050",
+"input": "\u0050",
+"output": [["Character", "\u0050"]]},
+
+{"description": "Valid Unicode character U+0051",
+"input": "\u0051",
+"output": [["Character", "\u0051"]]},
+
+{"description": "Valid Unicode character U+0052",
+"input": "\u0052",
+"output": [["Character", "\u0052"]]},
+
+{"description": "Valid Unicode character U+0053",
+"input": "\u0053",
+"output": [["Character", "\u0053"]]},
+
+{"description": "Valid Unicode character U+0054",
+"input": "\u0054",
+"output": [["Character", "\u0054"]]},
+
+{"description": "Valid Unicode character U+0055",
+"input": "\u0055",
+"output": [["Character", "\u0055"]]},
+
+{"description": "Valid Unicode character U+0056",
+"input": "\u0056",
+"output": [["Character", "\u0056"]]},
+
+{"description": "Valid Unicode character U+0057",
+"input": "\u0057",
+"output": [["Character", "\u0057"]]},
+
+{"description": "Valid Unicode character U+0058",
+"input": "\u0058",
+"output": [["Character", "\u0058"]]},
+
+{"description": "Valid Unicode character U+0059",
+"input": "\u0059",
+"output": [["Character", "\u0059"]]},
+
+{"description": "Valid Unicode character U+005A",
+"input": "\u005A",
+"output": [["Character", "\u005A"]]},
+
+{"description": "Valid Unicode character U+005B",
+"input": "\u005B",
+"output": [["Character", "\u005B"]]},
+
+{"description": "Valid Unicode character U+005C",
+"input": "\u005C",
+"output": [["Character", "\u005C"]]},
+
+{"description": "Valid Unicode character U+005D",
+"input": "\u005D",
+"output": [["Character", "\u005D"]]},
+
+{"description": "Valid Unicode character U+005E",
+"input": "\u005E",
+"output": [["Character", "\u005E"]]},
+
+{"description": "Valid Unicode character U+005F",
+"input": "\u005F",
+"output": [["Character", "\u005F"]]},
+
+{"description": "Valid Unicode character U+0060",
+"input": "\u0060",
+"output": [["Character", "\u0060"]]},
+
+{"description": "Valid Unicode character U+0061",
+"input": "\u0061",
+"output": [["Character", "\u0061"]]},
+
+{"description": "Valid Unicode character U+0062",
+"input": "\u0062",
+"output": [["Character", "\u0062"]]},
+
+{"description": "Valid Unicode character U+0063",
+"input": "\u0063",
+"output": [["Character", "\u0063"]]},
+
+{"description": "Valid Unicode character U+0064",
+"input": "\u0064",
+"output": [["Character", "\u0064"]]},
+
+{"description": "Valid Unicode character U+0065",
+"input": "\u0065",
+"output": [["Character", "\u0065"]]},
+
+{"description": "Valid Unicode character U+0066",
+"input": "\u0066",
+"output": [["Character", "\u0066"]]},
+
+{"description": "Valid Unicode character U+0067",
+"input": "\u0067",
+"output": [["Character", "\u0067"]]},
+
+{"description": "Valid Unicode character U+0068",
+"input": "\u0068",
+"output": [["Character", "\u0068"]]},
+
+{"description": "Valid Unicode character U+0069",
+"input": "\u0069",
+"output": [["Character", "\u0069"]]},
+
+{"description": "Valid Unicode character U+006A",
+"input": "\u006A",
+"output": [["Character", "\u006A"]]},
+
+{"description": "Valid Unicode character U+006B",
+"input": "\u006B",
+"output": [["Character", "\u006B"]]},
+
+{"description": "Valid Unicode character U+006C",
+"input": "\u006C",
+"output": [["Character", "\u006C"]]},
+
+{"description": "Valid Unicode character U+006D",
+"input": "\u006D",
+"output": [["Character", "\u006D"]]},
+
+{"description": "Valid Unicode character U+006E",
+"input": "\u006E",
+"output": [["Character", "\u006E"]]},
+
+{"description": "Valid Unicode character U+006F",
+"input": "\u006F",
+"output": [["Character", "\u006F"]]},
+
+{"description": "Valid Unicode character U+0070",
+"input": "\u0070",
+"output": [["Character", "\u0070"]]},
+
+{"description": "Valid Unicode character U+0071",
+"input": "\u0071",
+"output": [["Character", "\u0071"]]},
+
+{"description": "Valid Unicode character U+0072",
+"input": "\u0072",
+"output": [["Character", "\u0072"]]},
+
+{"description": "Valid Unicode character U+0073",
+"input": "\u0073",
+"output": [["Character", "\u0073"]]},
+
+{"description": "Valid Unicode character U+0074",
+"input": "\u0074",
+"output": [["Character", "\u0074"]]},
+
+{"description": "Valid Unicode character U+0075",
+"input": "\u0075",
+"output": [["Character", "\u0075"]]},
+
+{"description": "Valid Unicode character U+0076",
+"input": "\u0076",
+"output": [["Character", "\u0076"]]},
+
+{"description": "Valid Unicode character U+0077",
+"input": "\u0077",
+"output": [["Character", "\u0077"]]},
+
+{"description": "Valid Unicode character U+0078",
+"input": "\u0078",
+"output": [["Character", "\u0078"]]},
+
+{"description": "Valid Unicode character U+0079",
+"input": "\u0079",
+"output": [["Character", "\u0079"]]},
+
+{"description": "Valid Unicode character U+007A",
+"input": "\u007A",
+"output": [["Character", "\u007A"]]},
+
+{"description": "Valid Unicode character U+007B",
+"input": "\u007B",
+"output": [["Character", "\u007B"]]},
+
+{"description": "Valid Unicode character U+007C",
+"input": "\u007C",
+"output": [["Character", "\u007C"]]},
+
+{"description": "Valid Unicode character U+007D",
+"input": "\u007D",
+"output": [["Character", "\u007D"]]},
+
+{"description": "Valid Unicode character U+007E",
+"input": "\u007E",
+"output": [["Character", "\u007E"]]},
+
+{"description": "Valid Unicode character U+00A0",
+"input": "\u00A0",
+"output": [["Character", "\u00A0"]]},
+
+{"description": "Valid Unicode character U+00A1",
+"input": "\u00A1",
+"output": [["Character", "\u00A1"]]},
+
+{"description": "Valid Unicode character U+00A2",
+"input": "\u00A2",
+"output": [["Character", "\u00A2"]]},
+
+{"description": "Valid Unicode character U+00A3",
+"input": "\u00A3",
+"output": [["Character", "\u00A3"]]},
+
+{"description": "Valid Unicode character U+00A4",
+"input": "\u00A4",
+"output": [["Character", "\u00A4"]]},
+
+{"description": "Valid Unicode character U+00A5",
+"input": "\u00A5",
+"output": [["Character", "\u00A5"]]},
+
+{"description": "Valid Unicode character U+00A6",
+"input": "\u00A6",
+"output": [["Character", "\u00A6"]]},
+
+{"description": "Valid Unicode character U+00A7",
+"input": "\u00A7",
+"output": [["Character", "\u00A7"]]},
+
+{"description": "Valid Unicode character U+00A8",
+"input": "\u00A8",
+"output": [["Character", "\u00A8"]]},
+
+{"description": "Valid Unicode character U+00A9",
+"input": "\u00A9",
+"output": [["Character", "\u00A9"]]},
+
+{"description": "Valid Unicode character U+00AA",
+"input": "\u00AA",
+"output": [["Character", "\u00AA"]]},
+
+{"description": "Valid Unicode character U+00AB",
+"input": "\u00AB",
+"output": [["Character", "\u00AB"]]},
+
+{"description": "Valid Unicode character U+00AC",
+"input": "\u00AC",
+"output": [["Character", "\u00AC"]]},
+
+{"description": "Valid Unicode character U+00AD",
+"input": "\u00AD",
+"output": [["Character", "\u00AD"]]},
+
+{"description": "Valid Unicode character U+00AE",
+"input": "\u00AE",
+"output": [["Character", "\u00AE"]]},
+
+{"description": "Valid Unicode character U+00AF",
+"input": "\u00AF",
+"output": [["Character", "\u00AF"]]},
+
+{"description": "Valid Unicode character U+00B0",
+"input": "\u00B0",
+"output": [["Character", "\u00B0"]]},
+
+{"description": "Valid Unicode character U+00B1",
+"input": "\u00B1",
+"output": [["Character", "\u00B1"]]},
+
+{"description": "Valid Unicode character U+00B2",
+"input": "\u00B2",
+"output": [["Character", "\u00B2"]]},
+
+{"description": "Valid Unicode character U+00B3",
+"input": "\u00B3",
+"output": [["Character", "\u00B3"]]},
+
+{"description": "Valid Unicode character U+00B4",
+"input": "\u00B4",
+"output": [["Character", "\u00B4"]]},
+
+{"description": "Valid Unicode character U+00B5",
+"input": "\u00B5",
+"output": [["Character", "\u00B5"]]},
+
+{"description": "Valid Unicode character U+00B6",
+"input": "\u00B6",
+"output": [["Character", "\u00B6"]]},
+
+{"description": "Valid Unicode character U+00B7",
+"input": "\u00B7",
+"output": [["Character", "\u00B7"]]},
+
+{"description": "Valid Unicode character U+00B8",
+"input": "\u00B8",
+"output": [["Character", "\u00B8"]]},
+
+{"description": "Valid Unicode character U+00B9",
+"input": "\u00B9",
+"output": [["Character", "\u00B9"]]},
+
+{"description": "Valid Unicode character U+00BA",
+"input": "\u00BA",
+"output": [["Character", "\u00BA"]]},
+
+{"description": "Valid Unicode character U+00BB",
+"input": "\u00BB",
+"output": [["Character", "\u00BB"]]},
+
+{"description": "Valid Unicode character U+00BC",
+"input": "\u00BC",
+"output": [["Character", "\u00BC"]]},
+
+{"description": "Valid Unicode character U+00BD",
+"input": "\u00BD",
+"output": [["Character", "\u00BD"]]},
+
+{"description": "Valid Unicode character U+00BE",
+"input": "\u00BE",
+"output": [["Character", "\u00BE"]]},
+
+{"description": "Valid Unicode character U+00BF",
+"input": "\u00BF",
+"output": [["Character", "\u00BF"]]},
+
+{"description": "Valid Unicode character U+00C0",
+"input": "\u00C0",
+"output": [["Character", "\u00C0"]]},
+
+{"description": "Valid Unicode character U+00C1",
+"input": "\u00C1",
+"output": [["Character", "\u00C1"]]},
+
+{"description": "Valid Unicode character U+00C2",
+"input": "\u00C2",
+"output": [["Character", "\u00C2"]]},
+
+{"description": "Valid Unicode character U+00C3",
+"input": "\u00C3",
+"output": [["Character", "\u00C3"]]},
+
+{"description": "Valid Unicode character U+00C4",
+"input": "\u00C4",
+"output": [["Character", "\u00C4"]]},
+
+{"description": "Valid Unicode character U+00C5",
+"input": "\u00C5",
+"output": [["Character", "\u00C5"]]},
+
+{"description": "Valid Unicode character U+00C6",
+"input": "\u00C6",
+"output": [["Character", "\u00C6"]]},
+
+{"description": "Valid Unicode character U+00C7",
+"input": "\u00C7",
+"output": [["Character", "\u00C7"]]},
+
+{"description": "Valid Unicode character U+00C8",
+"input": "\u00C8",
+"output": [["Character", "\u00C8"]]},
+
+{"description": "Valid Unicode character U+00C9",
+"input": "\u00C9",
+"output": [["Character", "\u00C9"]]},
+
+{"description": "Valid Unicode character U+00CA",
+"input": "\u00CA",
+"output": [["Character", "\u00CA"]]},
+
+{"description": "Valid Unicode character U+00CB",
+"input": "\u00CB",
+"output": [["Character", "\u00CB"]]},
+
+{"description": "Valid Unicode character U+00CC",
+"input": "\u00CC",
+"output": [["Character", "\u00CC"]]},
+
+{"description": "Valid Unicode character U+00CD",
+"input": "\u00CD",
+"output": [["Character", "\u00CD"]]},
+
+{"description": "Valid Unicode character U+00CE",
+"input": "\u00CE",
+"output": [["Character", "\u00CE"]]},
+
+{"description": "Valid Unicode character U+00CF",
+"input": "\u00CF",
+"output": [["Character", "\u00CF"]]},
+
+{"description": "Valid Unicode character U+00D0",
+"input": "\u00D0",
+"output": [["Character", "\u00D0"]]},
+
+{"description": "Valid Unicode character U+00D1",
+"input": "\u00D1",
+"output": [["Character", "\u00D1"]]},
+
+{"description": "Valid Unicode character U+00D2",
+"input": "\u00D2",
+"output": [["Character", "\u00D2"]]},
+
+{"description": "Valid Unicode character U+00D3",
+"input": "\u00D3",
+"output": [["Character", "\u00D3"]]},
+
+{"description": "Valid Unicode character U+00D4",
+"input": "\u00D4",
+"output": [["Character", "\u00D4"]]},
+
+{"description": "Valid Unicode character U+00D5",
+"input": "\u00D5",
+"output": [["Character", "\u00D5"]]},
+
+{"description": "Valid Unicode character U+00D6",
+"input": "\u00D6",
+"output": [["Character", "\u00D6"]]},
+
+{"description": "Valid Unicode character U+00D7",
+"input": "\u00D7",
+"output": [["Character", "\u00D7"]]},
+
+{"description": "Valid Unicode character U+00D8",
+"input": "\u00D8",
+"output": [["Character", "\u00D8"]]},
+
+{"description": "Valid Unicode character U+00D9",
+"input": "\u00D9",
+"output": [["Character", "\u00D9"]]},
+
+{"description": "Valid Unicode character U+00DA",
+"input": "\u00DA",
+"output": [["Character", "\u00DA"]]},
+
+{"description": "Valid Unicode character U+00DB",
+"input": "\u00DB",
+"output": [["Character", "\u00DB"]]},
+
+{"description": "Valid Unicode character U+00DC",
+"input": "\u00DC",
+"output": [["Character", "\u00DC"]]},
+
+{"description": "Valid Unicode character U+00DD",
+"input": "\u00DD",
+"output": [["Character", "\u00DD"]]},
+
+{"description": "Valid Unicode character U+00DE",
+"input": "\u00DE",
+"output": [["Character", "\u00DE"]]},
+
+{"description": "Valid Unicode character U+00DF",
+"input": "\u00DF",
+"output": [["Character", "\u00DF"]]},
+
+{"description": "Valid Unicode character U+00E0",
+"input": "\u00E0",
+"output": [["Character", "\u00E0"]]},
+
+{"description": "Valid Unicode character U+00E1",
+"input": "\u00E1",
+"output": [["Character", "\u00E1"]]},
+
+{"description": "Valid Unicode character U+00E2",
+"input": "\u00E2",
+"output": [["Character", "\u00E2"]]},
+
+{"description": "Valid Unicode character U+00E3",
+"input": "\u00E3",
+"output": [["Character", "\u00E3"]]},
+
+{"description": "Valid Unicode character U+00E4",
+"input": "\u00E4",
+"output": [["Character", "\u00E4"]]},
+
+{"description": "Valid Unicode character U+00E5",
+"input": "\u00E5",
+"output": [["Character", "\u00E5"]]},
+
+{"description": "Valid Unicode character U+00E6",
+"input": "\u00E6",
+"output": [["Character", "\u00E6"]]},
+
+{"description": "Valid Unicode character U+00E7",
+"input": "\u00E7",
+"output": [["Character", "\u00E7"]]},
+
+{"description": "Valid Unicode character U+00E8",
+"input": "\u00E8",
+"output": [["Character", "\u00E8"]]},
+
+{"description": "Valid Unicode character U+00E9",
+"input": "\u00E9",
+"output": [["Character", "\u00E9"]]},
+
+{"description": "Valid Unicode character U+00EA",
+"input": "\u00EA",
+"output": [["Character", "\u00EA"]]},
+
+{"description": "Valid Unicode character U+00EB",
+"input": "\u00EB",
+"output": [["Character", "\u00EB"]]},
+
+{"description": "Valid Unicode character U+00EC",
+"input": "\u00EC",
+"output": [["Character", "\u00EC"]]},
+
+{"description": "Valid Unicode character U+00ED",
+"input": "\u00ED",
+"output": [["Character", "\u00ED"]]},
+
+{"description": "Valid Unicode character U+00EE",
+"input": "\u00EE",
+"output": [["Character", "\u00EE"]]},
+
+{"description": "Valid Unicode character U+00EF",
+"input": "\u00EF",
+"output": [["Character", "\u00EF"]]},
+
+{"description": "Valid Unicode character U+00F0",
+"input": "\u00F0",
+"output": [["Character", "\u00F0"]]},
+
+{"description": "Valid Unicode character U+00F1",
+"input": "\u00F1",
+"output": [["Character", "\u00F1"]]},
+
+{"description": "Valid Unicode character U+00F2",
+"input": "\u00F2",
+"output": [["Character", "\u00F2"]]},
+
+{"description": "Valid Unicode character U+00F3",
+"input": "\u00F3",
+"output": [["Character", "\u00F3"]]},
+
+{"description": "Valid Unicode character U+00F4",
+"input": "\u00F4",
+"output": [["Character", "\u00F4"]]},
+
+{"description": "Valid Unicode character U+00F5",
+"input": "\u00F5",
+"output": [["Character", "\u00F5"]]},
+
+{"description": "Valid Unicode character U+00F6",
+"input": "\u00F6",
+"output": [["Character", "\u00F6"]]},
+
+{"description": "Valid Unicode character U+00F7",
+"input": "\u00F7",
+"output": [["Character", "\u00F7"]]},
+
+{"description": "Valid Unicode character U+00F8",
+"input": "\u00F8",
+"output": [["Character", "\u00F8"]]},
+
+{"description": "Valid Unicode character U+00F9",
+"input": "\u00F9",
+"output": [["Character", "\u00F9"]]},
+
+{"description": "Valid Unicode character U+00FA",
+"input": "\u00FA",
+"output": [["Character", "\u00FA"]]},
+
+{"description": "Valid Unicode character U+00FB",
+"input": "\u00FB",
+"output": [["Character", "\u00FB"]]},
+
+{"description": "Valid Unicode character U+00FC",
+"input": "\u00FC",
+"output": [["Character", "\u00FC"]]},
+
+{"description": "Valid Unicode character U+00FD",
+"input": "\u00FD",
+"output": [["Character", "\u00FD"]]},
+
+{"description": "Valid Unicode character U+00FE",
+"input": "\u00FE",
+"output": [["Character", "\u00FE"]]},
+
+{"description": "Valid Unicode character U+00FF",
+"input": "\u00FF",
+"output": [["Character", "\u00FF"]]},
+
+{"description": "Valid Unicode character U+D7FF",
+"input": "\uD7FF",
+"output": [["Character", "\uD7FF"]]},
+
+{"description": "Valid Unicode character U+E000",
+"input": "\uE000",
+"output": [["Character", "\uE000"]]},
+
+{"description": "Valid Unicode character U+FDCF",
+"input": "\uFDCF",
+"output": [["Character", "\uFDCF"]]},
+
+{"description": "Valid Unicode character U+FDF0",
+"input": "\uFDF0",
+"output": [["Character", "\uFDF0"]]},
+
+{"description": "Valid Unicode character U+FFFD",
+"input": "\uFFFD",
+"output": [["Character", "\uFFFD"]]},
+
+{"description": "Valid Unicode character U+10000",
+"input": "\uD800\uDC00",
+"output": [["Character", "\uD800\uDC00"]]},
+
+{"description": "Valid Unicode character U+1FFFD",
+"input": "\uD83F\uDFFD",
+"output": [["Character", "\uD83F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+20000",
+"input": "\uD840\uDC00",
+"output": [["Character", "\uD840\uDC00"]]},
+
+{"description": "Valid Unicode character U+2FFFD",
+"input": "\uD87F\uDFFD",
+"output": [["Character", "\uD87F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+30000",
+"input": "\uD880\uDC00",
+"output": [["Character", "\uD880\uDC00"]]},
+
+{"description": "Valid Unicode character U+3FFFD",
+"input": "\uD8BF\uDFFD",
+"output": [["Character", "\uD8BF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+40000",
+"input": "\uD8C0\uDC00",
+"output": [["Character", "\uD8C0\uDC00"]]},
+
+{"description": "Valid Unicode character U+4FFFD",
+"input": "\uD8FF\uDFFD",
+"output": [["Character", "\uD8FF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+50000",
+"input": "\uD900\uDC00",
+"output": [["Character", "\uD900\uDC00"]]},
+
+{"description": "Valid Unicode character U+5FFFD",
+"input": "\uD93F\uDFFD",
+"output": [["Character", "\uD93F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+60000",
+"input": "\uD940\uDC00",
+"output": [["Character", "\uD940\uDC00"]]},
+
+{"description": "Valid Unicode character U+6FFFD",
+"input": "\uD97F\uDFFD",
+"output": [["Character", "\uD97F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+70000",
+"input": "\uD980\uDC00",
+"output": [["Character", "\uD980\uDC00"]]},
+
+{"description": "Valid Unicode character U+7FFFD",
+"input": "\uD9BF\uDFFD",
+"output": [["Character", "\uD9BF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+80000",
+"input": "\uD9C0\uDC00",
+"output": [["Character", "\uD9C0\uDC00"]]},
+
+{"description": "Valid Unicode character U+8FFFD",
+"input": "\uD9FF\uDFFD",
+"output": [["Character", "\uD9FF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+90000",
+"input": "\uDA00\uDC00",
+"output": [["Character", "\uDA00\uDC00"]]},
+
+{"description": "Valid Unicode character U+9FFFD",
+"input": "\uDA3F\uDFFD",
+"output": [["Character", "\uDA3F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+A0000",
+"input": "\uDA40\uDC00",
+"output": [["Character", "\uDA40\uDC00"]]},
+
+{"description": "Valid Unicode character U+AFFFD",
+"input": "\uDA7F\uDFFD",
+"output": [["Character", "\uDA7F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+B0000",
+"input": "\uDA80\uDC00",
+"output": [["Character", "\uDA80\uDC00"]]},
+
+{"description": "Valid Unicode character U+BFFFD",
+"input": "\uDABF\uDFFD",
+"output": [["Character", "\uDABF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+C0000",
+"input": "\uDAC0\uDC00",
+"output": [["Character", "\uDAC0\uDC00"]]},
+
+{"description": "Valid Unicode character U+CFFFD",
+"input": "\uDAFF\uDFFD",
+"output": [["Character", "\uDAFF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+D0000",
+"input": "\uDB00\uDC00",
+"output": [["Character", "\uDB00\uDC00"]]},
+
+{"description": "Valid Unicode character U+DFFFD",
+"input": "\uDB3F\uDFFD",
+"output": [["Character", "\uDB3F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+E0000",
+"input": "\uDB40\uDC00",
+"output": [["Character", "\uDB40\uDC00"]]},
+
+{"description": "Valid Unicode character U+EFFFD",
+"input": "\uDB7F\uDFFD",
+"output": [["Character", "\uDB7F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+F0000",
+"input": "\uDB80\uDC00",
+"output": [["Character", "\uDB80\uDC00"]]},
+
+{"description": "Valid Unicode character U+FFFFD",
+"input": "\uDBBF\uDFFD",
+"output": [["Character", "\uDBBF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+100000",
+"input": "\uDBC0\uDC00",
+"output": [["Character", "\uDBC0\uDC00"]]},
+
+{"description": "Valid Unicode character U+10FFFD",
+"input": "\uDBFF\uDFFD",
+"output": [["Character", "\uDBFF\uDFFD"]]}
+
+]}
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/unicodeCharsProblematic.test b/pkg/third_party/html5lib/test/data/tokenizer/unicodeCharsProblematic.test
new file mode 100644
index 0000000..cf2fbe6
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/unicodeCharsProblematic.test
@@ -0,0 +1,27 @@
+{"tests" : [
+{"description": "Invalid Unicode character U+DFFF",
+"doubleEscaped":true,
+"input": "\\uDFFF",
+"output":["ParseError", ["Character", "\\uFFFD"]]},
+
+{"description": "Invalid Unicode character U+D800",
+"doubleEscaped":true,
+"input": "\\uD800",
+"output":["ParseError", ["Character", "\\uFFFD"]]},
+
+{"description": "Invalid Unicode character U+DFFF with valid preceding character",
+"doubleEscaped":true,
+"input": "a\\uDFFF",
+"output":["ParseError", ["Character", "a\\uFFFD"]]},
+
+{"description": "Invalid Unicode character U+D800 with valid following character",
+"doubleEscaped":true,
+"input": "\\uD800a",
+"output":["ParseError", ["Character", "\\uFFFDa"]]},
+
+{"description":"CR followed by U+0000",
+"input":"\r\u0000",
+"output":[["Character", "\n"], "ParseError", ["Character", "\u0000"]],
+"ignoreErrorOrder":true}
+]
+}
\ No newline at end of file
diff --git a/pkg/third_party/html5lib/test/data/tokenizer/xmlViolation.test b/pkg/third_party/html5lib/test/data/tokenizer/xmlViolation.test
new file mode 100644
index 0000000..137d964
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tokenizer/xmlViolation.test
@@ -0,0 +1,22 @@
+{"xmlViolationTests": [
+
+{"description":"Non-XML character",
+"input":"a\uFFFFb",
+"ignoreErrorOrder":true,
+"output":["ParseError",["Character","a\uFFFDb"]]},
+
+{"description":"Non-XML space",
+"input":"a\u000Cb",
+"ignoreErrorOrder":true,
+"output":[["Character","a b"]]},
+
+{"description":"Double hyphen in comment",
+"input":"<!-- foo -- bar -->",
+"output":["ParseError",["Comment"," foo - - bar "]]},
+
+{"description":"FF between attributes",
+"input":"<a b=''\u000Cc=''>",
+"output":[["StartTag","a",{"b":"","c":""}]]}
+]}
+
+
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/adoption01.dat b/pkg/third_party/html5lib/test/data/tree-construction/adoption01.dat
new file mode 100644
index 0000000..787e1b0
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/adoption01.dat
@@ -0,0 +1,194 @@
+#data
+<a><p></a></p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <p>
+|       <a>
+
+#data
+<a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <p>
+|       <a>
+|         "2"
+|       "3"
+
+#data
+<a>1<button>2</a>3</button>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <button>
+|       <a>
+|         "2"
+|       "3"
+
+#data
+<a>1<b>2</a>3</b>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|       <b>
+|         "2"
+|     <b>
+|       "3"
+
+#data
+<a>1<div>2<div>3</a>4</div>5</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <div>
+|       <a>
+|         "2"
+|       <div>
+|         <a>
+|           "3"
+|         "4"
+|       "5"
+
+#data
+<table><a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <p>
+|       <a>
+|         "2"
+|       "3"
+|     <table>
+
+#data
+<b><b><a><p></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <b>
+|         <a>
+|         <p>
+|           <a>
+
+#data
+<b><a><b><p></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <a>
+|         <b>
+|       <b>
+|         <p>
+|           <a>
+
+#data
+<a><b><b><p></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|         <b>
+|     <b>
+|       <b>
+|         <p>
+|           <a>
+
+#data
+<p>1<s id="A">2<b id="B">3</p>4</s>5</b>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "1"
+|       <s>
+|         id="A"
+|         "2"
+|         <b>
+|           id="B"
+|           "3"
+|     <s>
+|       id="A"
+|       <b>
+|         id="B"
+|         "4"
+|     <b>
+|       id="B"
+|       "5"
+
+#data
+<table><a>1<td>2</td>3</table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "1"
+|     <a>
+|       "3"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "2"
+
+#data
+<table>A<td>B</td>C</table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "AC"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "B"
+
+#data
+<a><svg><tr><input></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <svg svg>
+|         <svg tr>
+|           <svg input>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/adoption02.dat b/pkg/third_party/html5lib/test/data/tree-construction/adoption02.dat
new file mode 100644
index 0000000..d18151b
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/adoption02.dat
@@ -0,0 +1,31 @@
+#data
+<b>1<i>2<p>3</b>4
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "1"
+|       <i>
+|         "2"
+|     <i>
+|       <p>
+|         <b>
+|           "3"
+|         "4"
+
+#data
+<a><div><style></style><address><a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <div>
+|       <a>
+|         <style>
+|       <address>
+|         <a>
+|         <a>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/comments01.dat b/pkg/third_party/html5lib/test/data/tree-construction/comments01.dat
new file mode 100644
index 0000000..44f1876
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/comments01.dat
@@ -0,0 +1,135 @@
+#data
+FOO<!-- BAR -->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR --!>BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR --   >BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR --   >BAZ -->
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR -- <QUX> -- MUX  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX --!>BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR -- <QUX> -- MUX  -->
+|     "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR -- <QUX> -- MUX -- >BAZ -->
+
+#data
+FOO<!---->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  -->
+|     "BAZ"
+
+#data
+FOO<!--->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  -->
+|     "BAZ"
+
+#data
+FOO<!-->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  -->
+|     "BAZ"
+
+#data
+<?xml version="1.0">Hi
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+|   <head>
+|   <body>
+|     "Hi"
+
+#data
+<?xml version="1.0">
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?xml version
+#errors
+#document
+| <!-- ?xml version -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+FOO<!----->BAZ
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!-- - -->
+|     "BAZ"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/doctype01.dat b/pkg/third_party/html5lib/test/data/tree-construction/doctype01.dat
new file mode 100644
index 0000000..ae45732
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/doctype01.dat
@@ -0,0 +1,370 @@
+#data
+<!DOCTYPE html>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!dOctYpE HtMl>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPEhtml>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE>Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE >Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato taco "ddd>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato sYstEM>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato sYstEM    >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE   potato       sYstEM  ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM taco  >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM 'taco"'>Hello
+#errors
+#document
+| <!DOCTYPE potato "" "taco"">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "taco">Hello
+#errors
+#document
+| <!DOCTYPE potato "" "taco">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "tai'co">Hello
+#errors
+#document
+| <!DOCTYPE potato "" "tai'co">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato SYSTEMtaco "ddd">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato grass SYSTEM taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato pUbLIcgoof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC goof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "go'of">Hello
+#errors
+#document
+| <!DOCTYPE potato "go'of" "">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go'of'>Hello
+#errors
+#document
+| <!DOCTYPE potato "go" "">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go:hh   of' >Hello
+#errors
+#document
+| <!DOCTYPE potato "go:hh   of" "">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato "W3C-//dfdf" "">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+   "http://www.w3.org/TR/html4/strict.dtd">Hello
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE ...>Hello
+#errors
+#document
+| <!DOCTYPE ...>
+| <html>
+|   <head>
+|   <body>
+|     "Hello"
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [ 
+<!-- internal declarations -->
+]>
+#errors
+#document
+| <!DOCTYPE root-element>
+| <html>
+|   <head>
+|   <body>
+|     "]>"
+
+#data
+<!DOCTYPE html PUBLIC
+  "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
+    "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
+#errors
+#document
+| <!DOCTYPE html "" "http://www.w3.org/DTD/HTML4-strict.dtd">
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "Mine!"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+|   <head>
+|   <body>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/domjs-unsafe.dat b/pkg/third_party/html5lib/test/data/tree-construction/domjs-unsafe.dat
new file mode 100644
index 0000000..905b94e
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/domjs-unsafe.dat
Binary files differ
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/entities01.dat b/pkg/third_party/html5lib/test/data/tree-construction/entities01.dat
new file mode 100644
index 0000000..c8073b7
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/entities01.dat
@@ -0,0 +1,603 @@
+#data
+FOO&gt;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO>BAR"
+
+#data
+FOO&gtBAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO>BAR"
+
+#data
+FOO&gt BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO> BAR"
+
+#data
+FOO&gt;;;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO>;;BAR"
+
+#data
+I'm &notit; I tell you
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "I'm ¬it; I tell you"
+
+#data
+I'm &notin; I tell you
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "I'm ∉ I tell you"
+
+#data
+FOO& BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO& BAR"
+
+#data
+FOO&<BAR>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&"
+|     <bar>
+
+#data
+FOO&&&&gt;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&&&>BAR"
+
+#data
+FOO&#41;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO)BAR"
+
+#data
+FOO&#x41;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOABAR"
+
+#data
+FOO&#X41;BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOABAR"
+
+#data
+FOO&#BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#BAR"
+
+#data
+FOO&#ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#ZOO"
+
+#data
+FOO&#xBAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOºR"
+
+#data
+FOO&#xZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#xZOO"
+
+#data
+FOO&#XZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO&#XZOO"
+
+#data
+FOO&#41BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO)BAR"
+
+#data
+FOO&#x41BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO䆺R"
+
+#data
+FOO&#x41ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOAZOO"
+
+#data
+FOO&#x0000;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#x0078;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOxZOO"
+
+#data
+FOO&#x0079;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOyZOO"
+
+#data
+FOO&#x0080;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO€ZOO"
+
+#data
+FOO&#x0081;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOZOO"
+
+#data
+FOO&#x0082;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‚ZOO"
+
+#data
+FOO&#x0083;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOƒZOO"
+
+#data
+FOO&#x0084;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO„ZOO"
+
+#data
+FOO&#x0085;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO…ZOO"
+
+#data
+FOO&#x0086;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO†ZOO"
+
+#data
+FOO&#x0087;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‡ZOO"
+
+#data
+FOO&#x0088;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOˆZOO"
+
+#data
+FOO&#x0089;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‰ZOO"
+
+#data
+FOO&#x008A;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŠZOO"
+
+#data
+FOO&#x008B;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‹ZOO"
+
+#data
+FOO&#x008C;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŒZOO"
+
+#data
+FOO&#x008D;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOZOO"
+
+#data
+FOO&#x008E;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŽZOO"
+
+#data
+FOO&#x008F;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOZOO"
+
+#data
+FOO&#x0090;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOZOO"
+
+#data
+FOO&#x0091;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO‘ZOO"
+
+#data
+FOO&#x0092;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO’ZOO"
+
+#data
+FOO&#x0093;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO“ZOO"
+
+#data
+FOO&#x0094;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO”ZOO"
+
+#data
+FOO&#x0095;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO•ZOO"
+
+#data
+FOO&#x0096;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO–ZOO"
+
+#data
+FOO&#x0097;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO—ZOO"
+
+#data
+FOO&#x0098;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO˜ZOO"
+
+#data
+FOO&#x0099;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO™ZOO"
+
+#data
+FOO&#x009A;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOšZOO"
+
+#data
+FOO&#x009B;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO›ZOO"
+
+#data
+FOO&#x009C;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOœZOO"
+
+#data
+FOO&#x009D;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOZOO"
+
+#data
+FOO&#x009E;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOžZOO"
+
+#data
+FOO&#x009F;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOŸZOO"
+
+#data
+FOO&#x00A0;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO ZOO"
+
+#data
+FOO&#xD7FF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO퟿ZOO"
+
+#data
+FOO&#xD800;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xD801;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xDFFE;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xDFFF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xE000;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOOZOO"
+
+#data
+FOO&#x10FFFE;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO􏿾ZOO"
+
+#data
+FOO&#x1087D4;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO􈟔ZOO"
+
+#data
+FOO&#x10FFFF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO􏿿ZOO"
+
+#data
+FOO&#x110000;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
+
+#data
+FOO&#xFFFFFF;ZOO
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO�ZOO"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/entities02.dat b/pkg/third_party/html5lib/test/data/tree-construction/entities02.dat
new file mode 100644
index 0000000..e2fb42a
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/entities02.dat
@@ -0,0 +1,249 @@
+#data
+<div bar="ZZ&gt;YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>YY"
+
+#data
+<div bar="ZZ&"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&"
+
+#data
+<div bar='ZZ&'></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&"
+
+#data
+<div bar=ZZ&></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&"
+
+#data
+<div bar="ZZ&gt=YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gt=YY"
+
+#data
+<div bar="ZZ&gt0YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gt0YY"
+
+#data
+<div bar="ZZ&gt9YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gt9YY"
+
+#data
+<div bar="ZZ&gtaYY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gtaYY"
+
+#data
+<div bar="ZZ&gtZYY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&gtZYY"
+
+#data
+<div bar="ZZ&gt YY"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ> YY"
+
+#data
+<div bar="ZZ&gt"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>"
+
+#data
+<div bar='ZZ&gt'></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>"
+
+#data
+<div bar=ZZ&gt></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ>"
+
+#data
+<div bar="ZZ&pound_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&prod_id=23"
+
+#data
+<div bar="ZZ&pound;_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod;_id=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ∏_id=23"
+
+#data
+<div bar="ZZ&pound=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&pound=23"
+
+#data
+<div bar="ZZ&prod=23"></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       bar="ZZ&prod=23"
+
+#data
+<div>ZZ&pound_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ£_id=23"
+
+#data
+<div>ZZ&prod_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ&prod_id=23"
+
+#data
+<div>ZZ&pound;_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ£_id=23"
+
+#data
+<div>ZZ&prod;_id=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ∏_id=23"
+
+#data
+<div>ZZ&pound=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ£=23"
+
+#data
+<div>ZZ&prod=23</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "ZZ&prod=23"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/html5test-com.dat b/pkg/third_party/html5lib/test/data/tree-construction/html5test-com.dat
new file mode 100644
index 0000000..d7cb71d
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/html5test-com.dat
@@ -0,0 +1,246 @@
+#data
+<div<div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div<div>
+
+#data
+<div foo<bar=''>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo<bar=""
+
+#data
+<div foo=`bar`>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo="`bar`"
+
+#data
+<div \"foo=''>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       \"foo=""
+
+#data
+<a href='\nbar'></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="\nbar"
+
+#data
+<!DOCTYPE html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+&lang;&rang;
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "⟨⟩"
+
+#data
+&apos;
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "'"
+
+#data
+&ImaginaryI;
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "ⅈ"
+
+#data
+&Kopf;
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "𝕂"
+
+#data
+&notinva;
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "∉"
+
+#data
+<?import namespace="foo" implementation="#bar">
+#errors
+#document
+| <!-- ?import namespace="foo" implementation="#bar" -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!--foo--bar-->
+#errors
+#document
+| <!-- foo--bar -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<![CDATA[x]]>
+#errors
+#document
+| <!-- [CDATA[x]] -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<textarea><!--</textarea>--></textarea>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--"
+|     "-->"
+
+#data
+<textarea><!--</textarea>-->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--"
+|     "-->"
+
+#data
+<style><!--</style>--></style>
+#errors
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "-->"
+
+#data
+<style><!--</style>-->
+#errors
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "-->"
+
+#data
+<ul><li>A </li> <li>B</li></ul>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         "A "
+|       " "
+|       <li>
+|         "B"
+
+#data
+<table><form><input type=hidden><input></form><div></div></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|     <div>
+|     <table>
+|       <form>
+|       <input>
+|         type="hidden"
+
+#data
+<i>A<b>B<p></i>C</b>D
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "A"
+|       <b>
+|         "B"
+|     <b>
+|     <p>
+|       <b>
+|         <i>
+|         "C"
+|       "D"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<svg></svg>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<math></math>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/inbody01.dat b/pkg/third_party/html5lib/test/data/tree-construction/inbody01.dat
new file mode 100644
index 0000000..3f2bd37
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/inbody01.dat
@@ -0,0 +1,43 @@
+#data
+<button>1</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <button>
+|       "1"
+
+#data
+<foo>1<p>2</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       "1"
+|       <p>
+|         "2"
+
+#data
+<dd>1</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <dd>
+|       "1"
+
+#data
+<foo>1<dd>2</foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       "1"
+|       <dd>
+|         "2"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/isindex.dat b/pkg/third_party/html5lib/test/data/tree-construction/isindex.dat
new file mode 100644
index 0000000..88325ff
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/isindex.dat
@@ -0,0 +1,40 @@
+#data
+<isindex>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<isindex name="A" action="B" prompt="C" foo="D">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       action="B"
+|       <hr>
+|       <label>
+|         "C"
+|         <input>
+|           foo="D"
+|           name="isindex"
+|       <hr>
+
+#data
+<form><isindex>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/pending-spec-changes-plain-text-unsafe.dat b/pkg/third_party/html5lib/test/data/tree-construction/pending-spec-changes-plain-text-unsafe.dat
new file mode 100644
index 0000000..a5ebb1e
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/pending-spec-changes-plain-text-unsafe.dat
Binary files differ
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/pending-spec-changes.dat b/pkg/third_party/html5lib/test/data/tree-construction/pending-spec-changes.dat
new file mode 100644
index 0000000..5a92084
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/pending-spec-changes.dat
@@ -0,0 +1,52 @@
+#data
+<input type="hidden"><frameset>
+#errors
+21: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+31: “frameset” start tag seen.
+31: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><table><caption><svg>foo</table>bar
+#errors
+47: End tag “table” did not match the name of the current open element (“svg”).
+47: “table” closed but “caption” was still open.
+47: End tag “table” seen, but there were open elements.
+36: Unclosed element “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           "foo"
+|     "bar"
+
+#data
+<table><tr><td><svg><desc><td></desc><circle>
+#errors
+7: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+30: A table cell was implicitly closed, but there were open elements.
+26: Unclosed element “desc”.
+20: Unclosed element “svg”.
+37: Stray end tag “desc”.
+45: End of file seen and there were open elements.
+45: Unclosed element “circle”.
+7: Unclosed element “table”.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg desc>
+|           <td>
+|             <circle>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/plain-text-unsafe.dat b/pkg/third_party/html5lib/test/data/tree-construction/plain-text-unsafe.dat
new file mode 100644
index 0000000..04cc11f
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/plain-text-unsafe.dat
Binary files differ
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/scriptdata01.dat b/pkg/third_party/html5lib/test/data/tree-construction/scriptdata01.dat
new file mode 100644
index 0000000..76b67f4
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/scriptdata01.dat
@@ -0,0 +1,308 @@
+#data
+FOO<script>'Hello'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'Hello'"
+|     "BAR"
+
+#data
+FOO<script></script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script></script >BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script></script/>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script></script/ >BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script type="text/plain"></scriptx>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "</scriptx>BAR"
+
+#data
+FOO<script></script foo=">" dd>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|     "BAR"
+
+#data
+FOO<script>'<'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<'"
+|     "BAR"
+
+#data
+FOO<script>'<!'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!'"
+|     "BAR"
+
+#data
+FOO<script>'<!-'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-'"
+|     "BAR"
+
+#data
+FOO<script>'<!--'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!--'"
+|     "BAR"
+
+#data
+FOO<script>'<!---'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!---'"
+|     "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-->'"
+|     "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-->'"
+|     "BAR"
+
+#data
+FOO<script>'<!-- potato'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-- potato'"
+|     "BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-- <sCrIpt'"
+|     "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> -'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> --'</script>BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt> -->'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       "'<!-- <sCrIpt> -->'"
+|     "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> --!>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt> -- >'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt '</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt/'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt\'"
+|     "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <script>
+|       type="text/plain"
+|       "'<!-- <sCrIpt/'</script>BAR"
+|     "QUX"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/scripted/adoption01.dat b/pkg/third_party/html5lib/test/data/tree-construction/scripted/adoption01.dat
new file mode 100644
index 0000000..4e08d0e
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/scripted/adoption01.dat
@@ -0,0 +1,15 @@
+#data
+<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         id="B"
+|         <script>
+|           "document.getElementById("A").id = "B""
+|     <b>
+|       id="A"
+|       "TEXT"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/scripted/ark.dat b/pkg/third_party/html5lib/test/data/tree-construction/scripted/ark.dat
new file mode 100644
index 0000000..acbac41
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/scripted/ark.dat
@@ -0,0 +1,26 @@
+#data
+<p><font size=4><font size=4><font size=4><script>document.getElementsByTagName("font")[2].setAttribute("size", "5");</script><font size=4><p>X
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="5"
+|             <script>
+|               "document.getElementsByTagName("font")[2].setAttribute("size", "5");"
+|             <font>
+|               size="4"
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             "X"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/scripted/webkit01.dat b/pkg/third_party/html5lib/test/data/tree-construction/scripted/webkit01.dat
new file mode 100644
index 0000000..ef4a41c
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/scripted/webkit01.dat
@@ -0,0 +1,28 @@
+#data
+1<script>document.write("2")</script>3
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "1"
+|     <script>
+|       "document.write("2")"
+|     "23"
+
+#data
+1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "1"
+|     <script>
+|       "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
+|     <script>
+|       "document.write('2')"
+|     "2"
+|     <script>
+|       "document.write('3')"
+|     "34"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tables01.dat b/pkg/third_party/html5lib/test/data/tree-construction/tables01.dat
new file mode 100644
index 0000000..c4b47e4
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tables01.dat
@@ -0,0 +1,212 @@
+#data
+<table><th>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <th>
+
+#data
+<table><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><col foo='bar'>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|         <col>
+|           foo="bar"
+
+#data
+<table><colgroup></html>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "foo"
+|     <table>
+|       <colgroup>
+
+#data
+<table></table><p>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|     <p>
+|       "foo"
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><select><option>3</select></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|         "3"
+|     <table>
+
+#data
+<table><select><table></table></select></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+|     <table>
+
+#data
+<table><select></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+
+#data
+<table><select><option>A<tr><td>B</td></tr></table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|         "A"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "B"
+
+#data
+<table><td></body></caption></col></colgroup></html>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "foo"
+
+#data
+<table><td>A</table>B
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "A"
+|     "B"
+
+#data
+<table><tr><caption>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|       <caption>
+
+#data
+<table><tr></body></caption></col></colgroup></html></td></th><td>foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "foo"
+
+#data
+<table><td><tr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|         <tr>
+
+#data
+<table><td><button><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <button>
+|           <td>
+
+#data
+<table><tr><td><svg><desc><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg desc>
+|           <td>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests1.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests1.dat
new file mode 100644
index 0000000..cbf8bdd
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests1.dat
@@ -0,0 +1,1952 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "Test"
+
+#data
+<p>One<p>Two
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "One"
+|     <p>
+|       "Two"
+
+#data
+Line1<br>Line2<br>Line3<br>Line4
+#errors
+Line: 1 Col: 5 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "Line1"
+|     <br>
+|     "Line2"
+|     <br>
+|     "Line3"
+|     <br>
+|     "Line4"
+
+#data
+<html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></head><body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></head><body></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (body).
+Line: 1 Col: 26 Unexpected end tag (html).
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><head><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<html><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<head></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+</head>
+#errors
+Line: 1 Col: 7 Unexpected end tag (head). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+</body>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (body) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+</html>
+#errors
+Line: 1 Col: 7 Unexpected end tag (html). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+
+#data
+<b><table><td></b><i></table>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 30 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+|       "X"
+
+#data
+<h1>Hello<h2>World
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Heading cannot be a child of another heading.
+18: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|       "Hello"
+|     <h2>
+|       "World"
+
+#data
+<a><p>X<a>Y</a>Z</p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 10 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <p>
+|       <a>
+|         "X"
+|       <a>
+|         "Y"
+|       "Z"
+
+#data
+<b><button>foo</b>bar
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <button>
+|       <b>
+|         "foo"
+|       "bar"
+
+#data
+<!DOCTYPE html><span><button>foo</span>bar
+#errors
+39: End tag “span” seen but there were unclosed elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <span>
+|       <button>
+|         "foobar"
+
+#data
+<p><b><div><marquee></p></b></div>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|     <div>
+|       <b>
+|         <marquee>
+|           <p>
+|           "X"
+
+#data
+<script><div></script></div><title><p></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end tag (div). Ignored.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<div>"
+|     <title>
+|       "<p>"
+|   <body>
+|     <p>
+|     <p>
+
+#data
+<!--><div>--<!-->
+#errors
+Line: 1 Col: 5 Incorrect comment.
+Line: 1 Col: 10 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Incorrect comment.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <!--  -->
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "--"
+|       <!--  -->
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <hr>
+|     <p>
+
+#data
+<select><b><option><select><option></b></select>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 49 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|     <option>
+|       "X"
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 63 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 64 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <a>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <a>
+|                 <table>
+|               <a>
+|     <a>
+|       <b>
+|         "X"
+|       "C"
+|     <a>
+|       "Y"
+
+#data
+<a X>0<b>1<a Y>2
+#errors
+Line: 1 Col: 5 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       x=""
+|       "0"
+|       <b>
+|         "1"
+|     <b>
+|       <a>
+|         y=""
+|         "2"
+
+#data
+<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->
+#errors
+Line: 1 Col: 7 Unexpected '-' after '--' found in comment.
+Line: 1 Col: 14 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected start tag (b) in table context caused voodoo mode.
+Line: 1 Col: 48 Unexpected implied end tag (b) in the table phase.
+Line: 1 Col: 48 Unexpected table cell start tag (th) in the table body phase.
+Line: 1 Col: 63 Got table cell end tag (th) while required end tags are missing.
+Line: 1 Col: 71 Unexpected end of file. Expected table content.
+#document
+| <!-- - -->
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <div>
+|         "helloexcite!"
+|         <b>
+|           "me!"
+|         <table>
+|           <tbody>
+|             <tr>
+|               <th>
+|                 <i>
+|                   "please!"
+|             <!-- X -->
+
+#data
+<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->
+#errors
+Line: 1 Col: 61 Unexpected end tag (li). Missing end tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <li>
+|       "hello"
+|     <li>
+|       "world"
+|       <ul>
+|         "how"
+|         <li>
+|           "do"
+|       "you"
+|   <!-- do -->
+
+#data
+<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E
+#errors
+Line: 1 Col: 54 Unexpected end tag (option) in the select phase. Ignored.
+Line: 1 Col: 55 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "A"
+|     <option>
+|       "B"
+|     <optgroup>
+|       "C"
+|       <select>
+|         "DE"
+
+#data
+<
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "<"
+
+#data
+<#
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "<#"
+
+#data
+</
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected end of file.
+Line: 1 Col: 2 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "</"
+
+#data
+</#
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character '#' found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ? -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?#
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?# -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!--  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!#
+#errors
+Line: 1 Col: 3 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?COMMENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 11 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COMMENT? -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!COMMENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 10 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+</ COMMENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!--  COMMENT  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<?COM--MENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 13 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COM--MENT? -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!COM--MENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+</ COM--MENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 14 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!--  COM--MENT  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><style> EOF
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       " EOF"
+|   <body>
+
+#data
+<!DOCTYPE html><script> <!-- </script> --> </script> EOF
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       " <!-- "
+|     " "
+|   <body>
+|     "-->  EOF"
+
+#data
+<b><p></b>TEST
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 10 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <p>
+|       <b>
+|       "TEST"
+
+#data
+<p id=a><b><p id=b></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (p). Ignored.
+Line: 1 Col: 23 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       id="a"
+|       <b>
+|     <p>
+|       id="b"
+|       "TEST"
+
+#data
+<b id=a><p><b id=b></p></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (p). Ignored.
+Line: 1 Col: 27 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 31 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       id="a"
+|       <p>
+|         <b>
+|           id="b"
+|       "TEST"
+
+#data
+<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>
+#errors
+Line: 1 Col: 61 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "U-test"
+|   <body>
+|     <div>
+|       <p>
+|         "Test"
+|         <u>
+
+#data
+<!DOCTYPE html><font><table></font></table></font>
+#errors
+Line: 1 Col: 35 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 35 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <table>
+
+#data
+<font><p>hello<b>cruel</font>world
+#errors
+Line: 1 Col: 6 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|     <p>
+|       <font>
+|         "hello"
+|         <b>
+|           "cruel"
+|       <b>
+|         "world"
+
+#data
+<b>Test</i>Test
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 11 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "TestTest"
+
+#data
+<b>A<cite>B<div>C
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "A"
+|       <cite>
+|         "B"
+|         <div>
+|           "C"
+
+#data
+<b>A<cite>B<div>C</cite>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end tag (cite). Ignored.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "A"
+|       <cite>
+|         "B"
+|         <div>
+|           "CD"
+
+#data
+<b>A<cite>B<div>C</b>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 21 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "A"
+|       <cite>
+|         "B"
+|     <div>
+|       <b>
+|         "C"
+|       "D"
+
+#data
+
+#errors
+Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<DIV>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 5 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<DIV> abc
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 9 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc"
+
+#data
+<DIV> abc <B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+
+#data
+<DIV> abc <B> def
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def"
+
+#data
+<DIV> abc <B> def <I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+
+#data
+<DIV> abc <B> def <I> ghi
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi"
+
+#data
+<DIV> abc <B> def <I> ghi <P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|           <p>
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|           <p>
+|             " jkl"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|         <p>
+|           <b>
+|             " jkl "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|         <p>
+|           <b>
+|             " jkl "
+|           " mno"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+|         " pqr"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+|         " pqr "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 60 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       " abc "
+|       <b>
+|         " def "
+|         <i>
+|           " ghi "
+|       <i>
+|       <p>
+|         <i>
+|           <b>
+|             " jkl "
+|           " mno "
+|         " pqr "
+|       " stu"
+
+#data
+<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
+#errors
+Line: 1 Col: 1040 Unexpected start tag (test). Expected DOCTYPE.
+Line: 1 Col: 1040 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <test>
+|       attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------=""
+
+#data
+<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 39 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 39 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 39 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 45 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="blah"
+|       "aba"
+|       <a>
+|         href="foo"
+|         "br"
+|       <a>
+|         href="foo"
+|         "x"
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|     <a>
+|       href="foo"
+|       "aoe"
+
+#data
+<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 60 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="blah"
+|       "abax"
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <a>
+|                 href="foo"
+|                 "br"
+|       "aoe"
+
+#data
+<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 29 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="blah"
+|       "aba"
+|     <a>
+|       href="blah"
+|       "x"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <a>
+|               href="foo"
+|               "br"
+|     <a>
+|       href="blah"
+|       "aoe"
+
+#data
+<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa
+#errors
+Line: 1 Col: 10 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 45 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="a"
+|       "aa"
+|       <marquee>
+|         "aa"
+|         <a>
+|           href="b"
+|           "bb"
+|       "aa"
+
+#data
+<wbr><strike><code></strike><code><strike></code>
+#errors
+Line: 1 Col: 5 Unexpected start tag (wbr). Expected DOCTYPE.
+Line: 1 Col: 28 End tag (strike) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 49 Unexpected end tag (code). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <wbr>
+|     <strike>
+|       <code>
+|     <code>
+|       <code>
+|         <strike>
+
+#data
+<!DOCTYPE html><spacer>foo
+#errors
+26: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <spacer>
+|       "foo"
+
+#data
+<title><meta></title><link><title><meta></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<meta>"
+|     <link>
+|     <title>
+|       "<meta>"
+|   <body>
+
+#data
+<style><!--</style><meta><script>--><link></script>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|     <meta>
+|     <script>
+|       "--><link>"
+|   <body>
+
+#data
+<head><meta></head><link>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected start tag (link) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <meta>
+|     <link>
+|   <body>
+
+#data
+<table><tr><tr><td><td><span><th><span>X</table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 33 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 48 Got table cell end tag (th) while required end tags are missing.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|         <tr>
+|           <td>
+|           <td>
+|             <span>
+|           <th>
+|             <span>
+|               "X"
+
+#data
+<body><body><base><link><meta><title><p></title><body><p></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (body).
+Line: 1 Col: 54 Unexpected start tag (body).
+Line: 1 Col: 64 Unexpected end tag (p). Missing end tag (body).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <base>
+|     <link>
+|     <meta>
+|     <title>
+|       "<p>"
+|     <p>
+
+#data
+<textarea><p></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<p>"
+
+#data
+<p><image></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (image). Treated as img.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <img>
+
+#data
+<a><table><a></table><p><a><div><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 13 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 13 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 21 Unexpected end tag (table). Expected end tag (a).
+Line: 1 Col: 27 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 27 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 32 Unexpected end tag (p). Ignored.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 35 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <a>
+|       <table>
+|     <p>
+|       <a>
+|     <div>
+|       <a>
+
+#data
+<head></p><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end tag (p). Ignored.
+#document
+| <html>
+|   <head>
+|     <meta>
+|   <body>
+|     <p>
+
+#data
+<head></html><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected start tag (meta).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+|     <p>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+
+#data
+<b><table><td></b><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <i>
+
+#data
+<h1><h2>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+8: Heading cannot be a child of another heading.
+8: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|     <h2>
+
+#data
+<a><p><a></a></p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 9 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 21 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <p>
+|       <a>
+|       <a>
+
+#data
+<b><button></b></button></b>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <button>
+|       <b>
+
+#data
+<p><b><div><marquee></p></b></div>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|     <div>
+|       <b>
+|         <marquee>
+|           <p>
+
+#data
+<script></script></div><title></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (div). Ignored.
+#document
+| <html>
+|   <head>
+|     <script>
+|     <title>
+|   <body>
+|     <p>
+|     <p>
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <hr>
+|     <p>
+
+#data
+<select><b><option><select><option></b></select>
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 48 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|     <option>
+
+#data
+<html><head><title></title><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|   <body>
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 54 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 54 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <a>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <a>
+|                 <table>
+|               <a>
+|     <a>
+
+#data
+<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>
+#errors
+Line: 1 Col: 4 Unexpected start tag (ul). Expected DOCTYPE.
+Line: 1 Col: 45 Missing end tag (div, li).
+Line: 1 Col: 58 Missing end tag (address, li).
+Line: 1 Col: 69 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|       <div>
+|         <li>
+|       <li>
+|       <li>
+|         <div>
+|       <li>
+|         <address>
+|       <li>
+|         <b>
+|           <em>
+|       <li>
+
+#data
+<ul><li><ul></li><li>a</li></ul></li></ul>
+#errors
+XXX: fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         <ul>
+|           <li>
+|             "a"
+
+#data
+<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+|     <frameset>
+|       <frame>
+|     <noframes>
+
+#data
+<h1><table><td><h3></table><h3></h1>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+15: “td” start tag in table body.
+27: Unclosed elements.
+31: Heading cannot be a child of another heading.
+36: End tag “h1” seen but there were unclosed elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|       <table>
+|         <tbody>
+|           <tr>
+|             <td>
+|               <h3>
+|     <h3>
+
+#data
+<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|         <col>
+|       <colgroup>
+|         <col>
+|         <col>
+|         <col>
+|       <colgroup>
+|         <col>
+|         <col>
+|       <thead>
+|         <tr>
+|           <td>
+
+#data
+<table><col><tbody><col><tr><col><td><col></table><col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 55 Unexpected start tag col. Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|         <col>
+|       <tbody>
+|       <colgroup>
+|         <col>
+|       <tbody>
+|         <tr>
+|       <colgroup>
+|         <col>
+|       <tbody>
+|         <tr>
+|           <td>
+|       <colgroup>
+|         <col>
+
+#data
+<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 52 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 80 Unexpected start tag colgroup. Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+|       <tbody>
+|       <colgroup>
+|       <tbody>
+|         <tr>
+|       <colgroup>
+|       <tbody>
+|         <tr>
+|           <td>
+|       <colgroup>
+
+#data
+</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>
+#errors
+Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
+Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
+Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
+Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
+Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
+Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
+Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
+Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
+Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
+Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
+Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
+Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
+Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
+Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
+Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
+Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
+Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
+Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
+Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
+Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
+Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
+Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 140 This element (img) has no end tag.
+Line: 1 Col: 148 Unexpected end tag (title). Ignored.
+Line: 1 Col: 155 Unexpected end tag (span). Ignored.
+Line: 1 Col: 163 Unexpected end tag (style). Ignored.
+Line: 1 Col: 172 Unexpected end tag (script). Ignored.
+Line: 1 Col: 180 Unexpected end tag (table). Ignored.
+Line: 1 Col: 185 Unexpected end tag (th). Ignored.
+Line: 1 Col: 190 Unexpected end tag (td). Ignored.
+Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 203 This element (frame) has no end tag.
+Line: 1 Col: 210 This element (area) has no end tag.
+Line: 1 Col: 217 Unexpected end tag (link). Ignored.
+Line: 1 Col: 225 This element (param) has no end tag.
+Line: 1 Col: 230 This element (hr) has no end tag.
+Line: 1 Col: 238 This element (input) has no end tag.
+Line: 1 Col: 244 Unexpected end tag (col). Ignored.
+Line: 1 Col: 251 Unexpected end tag (base). Ignored.
+Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 269 This element (basefont) has no end tag.
+Line: 1 Col: 279 This element (bgsound) has no end tag.
+Line: 1 Col: 287 This element (embed) has no end tag.
+Line: 1 Col: 296 This element (spacer) has no end tag.
+Line: 1 Col: 300 Unexpected end tag (p). Ignored.
+Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 460 This element (wbr) has no end tag.
+Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 513 Unexpected end tag (html). Ignored.
+Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 520 Unexpected end tag (head). Ignored.
+Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 537 This element (image) has no end tag.
+Line: 1 Col: 547 This element (isindex) has no end tag.
+Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 599 Unexpected end tag (option). Ignored.
+Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+|     <p>
+
+#data
+<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>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode.
+Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode.
+Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode.
+Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode.
+Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode.
+Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (blink). Ignored.
+Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode.
+Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode.
+Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag.
+Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode.
+Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode.
+Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode.
+Line: 1 Col: 99 Unexpected end tag (select). Ignored.
+Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode.
+Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag.
+Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode.
+Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag.
+Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode.
+Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag.
+Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode.
+Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag.
+Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode.
+Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag.
+Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode.
+Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag.
+Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored.
+Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode.
+Line: 1 Col: 141 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode.
+Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode.
+Line: 1 Col: 151 This element (img) has no end tag.
+Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode.
+Line: 1 Col: 159 Unexpected end tag (title). Ignored.
+Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 166 Unexpected end tag (span). Ignored.
+Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode.
+Line: 1 Col: 174 Unexpected end tag (style). Ignored.
+Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode.
+Line: 1 Col: 183 Unexpected end tag (script). Ignored.
+Line: 1 Col: 196 Unexpected end tag (th). Ignored.
+Line: 1 Col: 201 Unexpected end tag (td). Ignored.
+Line: 1 Col: 206 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 214 This element (frame) has no end tag.
+Line: 1 Col: 221 This element (area) has no end tag.
+Line: 1 Col: 228 Unexpected end tag (link). Ignored.
+Line: 1 Col: 236 This element (param) has no end tag.
+Line: 1 Col: 241 This element (hr) has no end tag.
+Line: 1 Col: 249 This element (input) has no end tag.
+Line: 1 Col: 255 Unexpected end tag (col). Ignored.
+Line: 1 Col: 262 Unexpected end tag (base). Ignored.
+Line: 1 Col: 269 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 280 This element (basefont) has no end tag.
+Line: 1 Col: 290 This element (bgsound) has no end tag.
+Line: 1 Col: 298 This element (embed) has no end tag.
+Line: 1 Col: 307 This element (spacer) has no end tag.
+Line: 1 Col: 311 Unexpected end tag (p). Ignored.
+Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 331 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 350 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 366 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 404 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 471 This element (wbr) has no end tag.
+Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 524 Unexpected end tag (html). Ignored.
+Line: 1 Col: 524 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 531 Unexpected end tag (head). Ignored.
+Line: 1 Col: 540 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 548 This element (image) has no end tag.
+Line: 1 Col: 558 This element (isindex) has no end tag.
+Line: 1 Col: 568 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 590 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 610 Unexpected end tag (option). Ignored.
+Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 633 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+|     <table>
+|       <tbody>
+|         <tr>
+|     <p>
+
+#data
+<frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests10.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests10.dat
new file mode 100644
index 0000000..4f8df86
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests10.dat
@@ -0,0 +1,799 @@
+#data
+<!DOCTYPE html><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<!DOCTYPE html><svg></svg><![CDATA[a]]>
+#errors
+29: Bogus comment
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <!-- [CDATA[a]] -->
+
+#data
+<!DOCTYPE html><body><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<!DOCTYPE html><body><select><svg></svg></select>
+#errors
+35: Stray “svg” start tag.
+42: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!DOCTYPE html><body><select><option><svg></svg></option></select>
+#errors
+43: Stray “svg” start tag.
+50: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!DOCTYPE html><body><table><svg></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+41: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+53: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+58: Stray end tag “g”.
+65: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>
+#errors
+41: Start tag “svg” seen in “table”.
+53: Stray end tag “g”.
+65: Stray end tag “g”.
+72: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <table>
+|       <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>
+#errors
+45: Start tag “svg” seen in “table”.
+57: Stray end tag “g”.
+69: Stray end tag “g”.
+76: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg g>
+|                 "foo"
+|               <svg g>
+|                 "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg g>
+|                 "foo"
+|               <svg g>
+|                 "bar"
+|             <p>
+|               "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           <svg g>
+|             "foo"
+|           <svg g>
+|             "bar"
+|         <p>
+|           "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+70: HTML start tag “p” in a foreign namespace context.
+81: “table” closed but “caption” was still open.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           <svg g>
+|             "foo"
+|           <svg g>
+|             "bar"
+|         <p>
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux
+#errors
+78: “table” closed but “caption” was still open.
+78: Unclosed elements on stack.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <svg svg>
+|           <svg g>
+|             "foo"
+|           <svg g>
+|             "bar"
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+44: Start tag “svg” seen in “table”.
+56: Stray end tag “g”.
+68: Stray end tag “g”.
+71: HTML start tag “p” in a foreign namespace context.
+71: Start tag “p” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <p>
+|       "baz"
+|     <table>
+|       <colgroup>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+50: Stray “svg” start tag.
+54: Stray “g” start tag.
+62: Stray end tag “g”
+66: Stray “g” start tag.
+74: Stray end tag “g”
+77: Stray “p” start tag.
+88: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <select>
+|               "foobarbaz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+36: Start tag “select” seen in “table”.
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+54: Stray end tag “g”
+58: Stray “g” start tag.
+66: Stray end tag “g”
+69: Stray “p” start tag.
+80: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "foobarbaz"
+|     <table>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz
+#errors
+41: Stray “svg” start tag.
+68: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz
+#errors
+34: Stray “svg” start tag.
+61: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg g>
+|         "foo"
+|       <svg g>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>
+#errors
+31: Stray “svg” start tag.
+35: Stray “g” start tag.
+40: Stray end tag “g”
+44: Stray “g” start tag.
+49: Stray end tag “g”
+52: Stray “p” start tag.
+58: Stray “span” start tag.
+58: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>
+#errors
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+51: Stray end tag “g”
+55: Stray “g” start tag.
+60: Stray end tag “g”
+63: Stray “p” start tag.
+69: Stray “span” start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     <svg svg>
+|       xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <svg svg>
+|       <svg g>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <svg svg>
+|       <svg g>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <svg svg>
+|       <svg g>
+|         xlink href="foo"
+|         xml lang="en"
+|       "bar"
+
+#data
+<svg></path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<div><svg></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|     "a"
+
+#data
+<div><svg><path></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|     "a"
+
+#data
+<div><svg><path></svg><path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|       <path>
+
+#data
+<div><svg><path><foreignObject><math></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|           <svg foreignObject>
+|             <math math>
+|               "a"
+
+#data
+<div><svg><path><foreignObject><p></div>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|           <svg foreignObject>
+|             <p>
+|               "a"
+
+#data
+<!DOCTYPE html><svg><desc><div><svg><ul>a
+#errors
+40: HTML start tag “ul” in a foreign namespace context.
+41: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg desc>
+|         <div>
+|           <svg svg>
+|           <ul>
+|             "a"
+
+#data
+<!DOCTYPE html><svg><desc><svg><ul>a
+#errors
+35: HTML start tag “ul” in a foreign namespace context.
+36: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg desc>
+|         <svg svg>
+|         <ul>
+|           "a"
+
+#data
+<!DOCTYPE html><p><svg><desc><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <svg svg>
+|         <svg desc>
+|           <p>
+
+#data
+<!DOCTYPE html><p><svg><title><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <svg svg>
+|         <svg title>
+|           <p>
+
+#data
+<div><svg><path><foreignObject><p></foreignObject><p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <svg svg>
+|         <svg path>
+|           <svg foreignObject>
+|             <p>
+|             <p>
+
+#data
+<math><mi><div><object><div><span></span></div></object></div></mi><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <div>
+|           <object>
+|             <div>
+|               <span>
+|       <math mi>
+
+#data
+<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <svg svg>
+|           <svg foreignObject>
+|             <div>
+|               <div>
+|       <math mi>
+
+#data
+<svg><script></script><path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg script>
+|       <svg path>
+
+#data
+<table><svg></svg><tr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<math><mi><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <math mglyph>
+
+#data
+<math><mi><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         <math malignmark>
+
+#data
+<math><mo><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mo>
+|         <math mglyph>
+
+#data
+<math><mo><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mo>
+|         <math malignmark>
+
+#data
+<math><mn><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mn>
+|         <math mglyph>
+
+#data
+<math><mn><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mn>
+|         <math malignmark>
+
+#data
+<math><ms><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math ms>
+|         <math mglyph>
+
+#data
+<math><ms><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math ms>
+|         <math malignmark>
+
+#data
+<math><mtext><mglyph>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mtext>
+|         <math mglyph>
+
+#data
+<math><mtext><malignmark>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mtext>
+|         <math malignmark>
+
+#data
+<math><annotation-xml><svg></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|       <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|           <svg foreignObject>
+|             <div>
+|               <math math>
+|                 <math mi>
+|               <span>
+|           <svg path>
+|       <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|           <svg foreignObject>
+|             <math math>
+|               <math mi>
+|                 <svg svg>
+|               <math mo>
+|             <span>
+|           <svg path>
+|       <math mi>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests11.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests11.dat
new file mode 100644
index 0000000..638cde4
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests11.dat
@@ -0,0 +1,482 @@
+#data
+<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' 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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       attributeName=""
+|       attributeType=""
+|       baseFrequency=""
+|       baseProfile=""
+|       calcMode=""
+|       clipPathUnits=""
+|       contentScriptType=""
+|       contentStyleType=""
+|       diffuseConstant=""
+|       edgeMode=""
+|       externalResourcesRequired=""
+|       filterRes=""
+|       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=""
+
+#data
+<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' 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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       attributeName=""
+|       attributeType=""
+|       baseFrequency=""
+|       baseProfile=""
+|       calcMode=""
+|       clipPathUnits=""
+|       contentScriptType=""
+|       contentStyleType=""
+|       diffuseConstant=""
+|       edgeMode=""
+|       externalResourcesRequired=""
+|       filterRes=""
+|       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=""
+
+#data
+<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' 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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       attributeName=""
+|       attributeType=""
+|       baseFrequency=""
+|       baseProfile=""
+|       calcMode=""
+|       clipPathUnits=""
+|       contentScriptType=""
+|       contentStyleType=""
+|       diffuseConstant=""
+|       edgeMode=""
+|       externalResourcesRequired=""
+|       filterRes=""
+|       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=""
+
+#data
+<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' 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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       attributename=""
+|       attributetype=""
+|       basefrequency=""
+|       baseprofile=""
+|       calcmode=""
+|       clippathunits=""
+|       contentscripttype=""
+|       contentstyletype=""
+|       diffuseconstant=""
+|       edgemode=""
+|       externalresourcesrequired=""
+|       filterres=""
+|       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=""
+
+#data
+<!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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg altGlyph>
+|       <svg altGlyphDef>
+|       <svg altGlyphItem>
+|       <svg animateColor>
+|       <svg animateMotion>
+|       <svg animateTransform>
+|       <svg clipPath>
+|       <svg feBlend>
+|       <svg feColorMatrix>
+|       <svg feComponentTransfer>
+|       <svg feComposite>
+|       <svg feConvolveMatrix>
+|       <svg feDiffuseLighting>
+|       <svg feDisplacementMap>
+|       <svg feDistantLight>
+|       <svg feFlood>
+|       <svg feFuncA>
+|       <svg feFuncB>
+|       <svg feFuncG>
+|       <svg feFuncR>
+|       <svg feGaussianBlur>
+|       <svg feImage>
+|       <svg feMerge>
+|       <svg feMergeNode>
+|       <svg feMorphology>
+|       <svg feOffset>
+|       <svg fePointLight>
+|       <svg feSpecularLighting>
+|       <svg feSpotLight>
+|       <svg feTile>
+|       <svg feTurbulence>
+|       <svg foreignObject>
+|       <svg glyphRef>
+|       <svg linearGradient>
+|       <svg radialGradient>
+|       <svg textPath>
+
+#data
+<!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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg altGlyph>
+|       <svg altGlyphDef>
+|       <svg altGlyphItem>
+|       <svg animateColor>
+|       <svg animateMotion>
+|       <svg animateTransform>
+|       <svg clipPath>
+|       <svg feBlend>
+|       <svg feColorMatrix>
+|       <svg feComponentTransfer>
+|       <svg feComposite>
+|       <svg feConvolveMatrix>
+|       <svg feDiffuseLighting>
+|       <svg feDisplacementMap>
+|       <svg feDistantLight>
+|       <svg feFlood>
+|       <svg feFuncA>
+|       <svg feFuncB>
+|       <svg feFuncG>
+|       <svg feFuncR>
+|       <svg feGaussianBlur>
+|       <svg feImage>
+|       <svg feMerge>
+|       <svg feMergeNode>
+|       <svg feMorphology>
+|       <svg feOffset>
+|       <svg fePointLight>
+|       <svg feSpecularLighting>
+|       <svg feSpotLight>
+|       <svg feTile>
+|       <svg feTurbulence>
+|       <svg foreignObject>
+|       <svg glyphRef>
+|       <svg linearGradient>
+|       <svg radialGradient>
+|       <svg textPath>
+
+#data
+<!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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg altGlyph>
+|       <svg altGlyphDef>
+|       <svg altGlyphItem>
+|       <svg animateColor>
+|       <svg animateMotion>
+|       <svg animateTransform>
+|       <svg clipPath>
+|       <svg feBlend>
+|       <svg feColorMatrix>
+|       <svg feComponentTransfer>
+|       <svg feComposite>
+|       <svg feConvolveMatrix>
+|       <svg feDiffuseLighting>
+|       <svg feDisplacementMap>
+|       <svg feDistantLight>
+|       <svg feFlood>
+|       <svg feFuncA>
+|       <svg feFuncB>
+|       <svg feFuncG>
+|       <svg feFuncR>
+|       <svg feGaussianBlur>
+|       <svg feImage>
+|       <svg feMerge>
+|       <svg feMergeNode>
+|       <svg feMorphology>
+|       <svg feOffset>
+|       <svg fePointLight>
+|       <svg feSpecularLighting>
+|       <svg feSpotLight>
+|       <svg feTile>
+|       <svg feTurbulence>
+|       <svg foreignObject>
+|       <svg glyphRef>
+|       <svg linearGradient>
+|       <svg radialGradient>
+|       <svg textPath>
+
+#data
+<!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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math altglyph>
+|       <math altglyphdef>
+|       <math altglyphitem>
+|       <math animatecolor>
+|       <math animatemotion>
+|       <math animatetransform>
+|       <math clippath>
+|       <math feblend>
+|       <math fecolormatrix>
+|       <math fecomponenttransfer>
+|       <math fecomposite>
+|       <math feconvolvematrix>
+|       <math fediffuselighting>
+|       <math fedisplacementmap>
+|       <math fedistantlight>
+|       <math feflood>
+|       <math fefunca>
+|       <math fefuncb>
+|       <math fefuncg>
+|       <math fefuncr>
+|       <math fegaussianblur>
+|       <math feimage>
+|       <math femerge>
+|       <math femergenode>
+|       <math femorphology>
+|       <math feoffset>
+|       <math fepointlight>
+|       <math fespecularlighting>
+|       <math fespotlight>
+|       <math fetile>
+|       <math feturbulence>
+|       <math foreignobject>
+|       <math glyphref>
+|       <math lineargradient>
+|       <math radialgradient>
+|       <math textpath>
+
+#data
+<!DOCTYPE html><body><svg><solidColor /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg solidcolor>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests12.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests12.dat
new file mode 100644
index 0000000..63107d2
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests12.dat
@@ -0,0 +1,62 @@
+#data
+<!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
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "foo"
+|       <math math>
+|         <math mtext>
+|           <i>
+|             "baz"
+|         <math annotation-xml>
+|           <svg svg>
+|             <svg desc>
+|               <b>
+|                 "eggs"
+|             <svg g>
+|               <svg foreignObject>
+|                 <p>
+|                   "spam"
+|                 <table>
+|                   <tbody>
+|                     <tr>
+|                       <td>
+|                         <img>
+|             <svg g>
+|               "quux"
+|       "bar"
+
+#data
+<!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
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "foo"
+|     <math math>
+|       <math mtext>
+|         <i>
+|           "baz"
+|       <math annotation-xml>
+|         <svg svg>
+|           <svg desc>
+|             <b>
+|               "eggs"
+|           <svg g>
+|             <svg foreignObject>
+|               <p>
+|                 "spam"
+|               <table>
+|                 <tbody>
+|                   <tr>
+|                     <td>
+|                       <img>
+|           <svg g>
+|             "quux"
+|     "bar"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests14.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests14.dat
new file mode 100644
index 0000000..b8713f8
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests14.dat
@@ -0,0 +1,74 @@
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xyz:abc>
+
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xyz:abc>
+|     <span>
+
+#data
+<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+|   abc:def="gh"
+|   <head>
+|   <body>
+|     <xyz:abc>
+
+#data
+<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+|   xml:lang="bar"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><html 123=456>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   123="456"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><html 123=456><html 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   123="456"
+|   789="012"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><html><body 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     789="012"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests15.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests15.dat
new file mode 100644
index 0000000..6ce1c0d
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests15.dat
@@ -0,0 +1,208 @@
+#data
+<!DOCTYPE html><p><b><i><u></p> <p>X
+#errors
+Line: 1 Col: 31 Unexpected end tag (p). Ignored.
+Line: 1 Col: 36 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         <i>
+|           <u>
+|     <b>
+|       <i>
+|         <u>
+|           " "
+|           <p>
+|             "X"
+
+#data
+<p><b><i><u></p>
+<p>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag (p). Ignored.
+Line: 2 Col: 4 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         <i>
+|           <u>
+|     <b>
+|       <i>
+|         <u>
+|           "
+"
+|           <p>
+|             "X"
+
+#data
+<!doctype html></html> <head>
+#errors
+Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " "
+
+#data
+<!doctype html></body><meta>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+
+#data
+<html></html><!-- foo -->
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+| <!--  foo  -->
+
+#data
+<!doctype html></body><title>X</title>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+
+#data
+<!doctype html><table> X<meta></table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " X"
+|     <meta>
+|     <table>
+
+#data
+<!doctype html><table> x</table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " x"
+|     <table>
+
+#data
+<!doctype html><table> x </table>
+#errors
+Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " x "
+|     <table>
+
+#data
+<!doctype html><table><tr> x</table>
+#errors
+Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " x"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table>X<style> <tr>x </style> </table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <table>
+|       <style>
+|         " <tr>x "
+|       " "
+
+#data
+<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>
+#errors
+Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <a>
+|         "foo"
+|       <table>
+|         " "
+|         <tbody>
+|           <tr>
+|             <td>
+|               "bar"
+|             " "
+
+#data
+<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>
+#errors
+6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Stray start tag “frame”.
+21: Stray end tag “frame”.
+29: Stray end tag “frame”.
+39: “frameset” start tag after “body” already open.
+105: End of file seen inside an [R]CDATA element.
+105: End of file seen and there were open elements.
+XXX: These errors are wrong, please fix me!
+#document
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+|     <frameset>
+|       <frame>
+|     <noframes>
+|       "</frameset><noframes>"
+
+#data
+<!DOCTYPE html><object></html>
+#errors
+1: Expected closing tag. Unexpected end of file
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <object>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests16.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests16.dat
new file mode 100644
index 0000000..c8ef66f
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests16.dat
@@ -0,0 +1,2299 @@
+#data
+<!doctype html><script>
+#errors
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<!doctype html><script>a
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "a"
+|   <body>
+
+#data
+<!doctype html><script><
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<"
+|   <body>
+
+#data
+<!doctype html><script></
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</"
+|   <body>
+
+#data
+<!doctype html><script></S
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</S"
+|   <body>
+
+#data
+<!doctype html><script></SC
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SC"
+|   <body>
+
+#data
+<!doctype html><script></SCR
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCR"
+|   <body>
+
+#data
+<!doctype html><script></SCRI
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCRI"
+|   <body>
+
+#data
+<!doctype html><script></SCRIP
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIP"
+|   <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIPT"
+|   <body>
+
+#data
+<!doctype html><script></SCRIPT 
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<!doctype html><script></s
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</s"
+|   <body>
+
+#data
+<!doctype html><script></sc
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</sc"
+|   <body>
+
+#data
+<!doctype html><script></scr
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</scr"
+|   <body>
+
+#data
+<!doctype html><script></scri
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</scri"
+|   <body>
+
+#data
+<!doctype html><script></scrip
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</scrip"
+|   <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "</script"
+|   <body>
+
+#data
+<!doctype html><script></script 
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<!doctype html><script><!
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!"
+|   <body>
+
+#data
+<!doctype html><script><!a
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!a"
+|   <body>
+
+#data
+<!doctype html><script><!-
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!-"
+|   <body>
+
+#data
+<!doctype html><script><!-a
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!-a"
+|   <body>
+
+#data
+<!doctype html><script><!--
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<!doctype html><script><!--a
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--a"
+|   <body>
+
+#data
+<!doctype html><script><!--<
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<"
+|   <body>
+
+#data
+<!doctype html><script><!--<a
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<a"
+|   <body>
+
+#data
+<!doctype html><script><!--</
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--</"
+|   <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--</script"
+|   <body>
+
+#data
+<!doctype html><script><!--</script 
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<!doctype html><script><!--<s
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<s"
+|   <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script 
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script <
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <"
+|   <body>
+
+#data
+<!doctype html><script><!--<script <a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </s
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </s"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 43 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </scripta
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </scripta"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script 
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script>
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script>"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script/
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script/"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script <
+#errors
+Line: 1 Col: 45 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script <a
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script 
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script/
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script </script </script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<!doctype html><script><!--<script -
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -"
+|   <body>
+
+#data
+<!doctype html><script><!--<script -a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script -<
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -<"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --a
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --a"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --<
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --<"
+|   <body>
+
+#data
+<!doctype html><script><!--<script -->
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --><
+#errors
+Line: 1 Col: 39 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --><"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></
+#errors
+Line: 1 Col: 40 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></script"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script 
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script/
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script --></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script><\/script>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script><\/script>-->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt>-->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>--><!--</script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>--><!--"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-- ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>-- >"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- -></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- ->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- - ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- - >"
+|   <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>->"
+|   <body>
+
+#data
+<!doctype html><script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 49 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script>--!></script>X"
+|   <body>
+
+#data
+<!doctype html><script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 59 Unexpected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<scr'+'ipt>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 57 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt></script>X"
+|   <body>
+
+#data
+<!doctype html><style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 52 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--<style>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><style><!--</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "X"
+
+#data
+<!doctype html><style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|   <body>
+|     "...-->"
+
+#data
+<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+|   <body>
+|     "X"
+
+#data
+<!doctype html><style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 66 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--...<style><!--...--!>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><style><!--...</style><!-- --><style>@import ...</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|     <!--   -->
+|     <style>
+|       "@import ..."
+|   <body>
+
+#data
+<!doctype html><style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 63 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "...<style><!--..."
+|     <!--   -->
+|   <body>
+
+#data
+<!doctype html><style>...<!--[if IE]><style>...</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <style>
+|       "...<!--[if IE]><style>..."
+|   <body>
+|     "X"
+
+#data
+<!doctype html><title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 52 Unexpected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "<!--<title>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><title>&lt;/title></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "</title>"
+|   <body>
+
+#data
+<!doctype html><title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "foo/title><link></head><body>X"
+|   <body>
+
+#data
+<!doctype html><noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noscript).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--<noscript>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--"
+|   <body>
+|     "X"
+|     <noscript>
+|       "-->"
+
+#data
+<!doctype html><noscript><iframe></noscript>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noscript>
+|       "<iframe>"
+|   <body>
+|     "X"
+
+#data
+<!doctype html><noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noframes).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noframes>
+|       "<!--<noframes>"
+|   <body>
+|     "-->"
+
+#data
+<!doctype html><noframes><body><script><!--...</script></body></noframes></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <noframes>
+|       "<body><script><!--...</script></body>"
+|   <body>
+
+#data
+<!doctype html><textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 64 Unexpected end tag (textarea).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--<textarea>"
+|     "-->"
+
+#data
+<!doctype html><textarea>&lt;/textarea></textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "</textarea>"
+
+#data
+<!doctype html><textarea>&lt;</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<"
+
+#data
+<!doctype html><textarea>a&lt;b</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "a<b"
+
+#data
+<!doctype html><iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 56 Unexpected end tag (iframe).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "<!--<iframe>"
+|     "-->"
+
+#data
+<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "...<!--X->...<!--/X->..."
+
+#data
+<!doctype html><xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 44 Unexpected end tag (xmp).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+|       "<!--<xmp>"
+|     "-->"
+
+#data
+<!doctype html><noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 60 Unexpected end tag (noembed).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <noembed>
+|       "<!--<noembed>"
+|     "-->"
+
+#data
+<script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<script>a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "a"
+|   <body>
+
+#data
+<script><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<"
+|   <body>
+
+#data
+<script></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</"
+|   <body>
+
+#data
+<script></S
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</S"
+|   <body>
+
+#data
+<script></SC
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SC"
+|   <body>
+
+#data
+<script></SCR
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCR"
+|   <body>
+
+#data
+<script></SCRI
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCRI"
+|   <body>
+
+#data
+<script></SCRIP
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIP"
+|   <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</SCRIPT"
+|   <body>
+
+#data
+<script></SCRIPT 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<script></s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</s"
+|   <body>
+
+#data
+<script></sc
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</sc"
+|   <body>
+
+#data
+<script></scr
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</scr"
+|   <body>
+
+#data
+<script></scri
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</scri"
+|   <body>
+
+#data
+<script></scrip
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</scrip"
+|   <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</script"
+|   <body>
+
+#data
+<script></script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<script><!
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!"
+|   <body>
+
+#data
+<script><!a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!a"
+|   <body>
+
+#data
+<script><!-
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!-"
+|   <body>
+
+#data
+<script><!-a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!-a"
+|   <body>
+
+#data
+<script><!--
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<script><!--a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--a"
+|   <body>
+
+#data
+<script><!--<
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<"
+|   <body>
+
+#data
+<script><!--<a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<a"
+|   <body>
+
+#data
+<script><!--</
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--</"
+|   <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--</script"
+|   <body>
+
+#data
+<script><!--</script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--"
+|   <body>
+
+#data
+<script><!--<s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<s"
+|   <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script"
+|   <body>
+
+#data
+<script><!--<script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script "
+|   <body>
+
+#data
+<script><!--<script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <"
+|   <body>
+
+#data
+<script><!--<script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script <a"
+|   <body>
+
+#data
+<script><!--<script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </"
+|   <body>
+
+#data
+<script><!--<script </s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </s"
+|   <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script"
+|   <body>
+
+#data
+<script><!--<script </scripta
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </scripta"
+|   <body>
+
+#data
+<script><!--<script </script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script>"
+|   <body>
+
+#data
+<script><!--<script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script/"
+|   <body>
+
+#data
+<script><!--<script </script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <"
+|   <body>
+
+#data
+<script><!--<script </script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script <a"
+|   <body>
+
+#data
+<script><!--<script </script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </"
+|   <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script </script"
+|   <body>
+
+#data
+<script><!--<script </script </script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script </script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script </script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script </script "
+|   <body>
+
+#data
+<script><!--<script -
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -"
+|   <body>
+
+#data
+<script><!--<script -a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -a"
+|   <body>
+
+#data
+<script><!--<script --
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --"
+|   <body>
+
+#data
+<script><!--<script --a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --a"
+|   <body>
+
+#data
+<script><!--<script -->
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script --><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --><"
+|   <body>
+
+#data
+<script><!--<script --></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></"
+|   <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script --></script"
+|   <body>
+
+#data
+<script><!--<script --></script 
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script --></script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script --></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script -->"
+|   <body>
+
+#data
+<script><!--<script><\/script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script><\/script>-->"
+|   <body>
+
+#data
+<script><!--<script></scr'+'ipt>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt>-->"
+|   <body>
+
+#data
+<script><!--<script></script><script></script></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>--><!--</script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>--><!--"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>-- ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>-- >"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>- -></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- ->"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>- - ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>- - >"
+|   <body>
+
+#data
+<script><!--<script></script><script></script>-></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></script><script></script>->"
+|   <body>
+
+#data
+<script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script>--!></script>X"
+|   <body>
+
+#data
+<script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 44 Unexpected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<scr'+'ipt>"
+|   <body>
+|     "-->"
+
+#data
+<script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 42 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "<!--<script></scr'+'ipt></script>X"
+|   <body>
+
+#data
+<style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--<style>"
+|   <body>
+|     "-->"
+
+#data
+<style><!--</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--"
+|   <body>
+|     "X"
+
+#data
+<style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 36 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|   <body>
+|     "...-->"
+
+#data
+<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+|   <body>
+|     "X"
+
+#data
+<style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--...<style><!--...--!>"
+|   <body>
+|     "-->"
+
+#data
+<style><!--...</style><!-- --><style>@import ...</style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "<!--..."
+|     <!--   -->
+|     <style>
+|       "@import ..."
+|   <body>
+
+#data
+<style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 48 Unexpected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       "...<style><!--..."
+|     <!--   -->
+|   <body>
+
+#data
+<style>...<!--[if IE]><style>...</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       "...<!--[if IE]><style>..."
+|   <body>
+|     "X"
+
+#data
+<title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<!--<title>"
+|   <body>
+|     "-->"
+
+#data
+<title>&lt;/title></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "</title>"
+|   <body>
+
+#data
+<title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "foo/title><link></head><body>X"
+|   <body>
+
+#data
+<noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noscript).
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--<noscript>"
+|   <body>
+|     "-->"
+
+#data
+<noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--"
+|   <body>
+|     "X"
+|     <noscript>
+|       "-->"
+
+#data
+<noscript><iframe></noscript>X
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<iframe>"
+|   <body>
+|     "X"
+
+#data
+<noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noframes).
+#document
+| <html>
+|   <head>
+|     <noframes>
+|       "<!--<noframes>"
+|   <body>
+|     "-->"
+
+#data
+<noframes><body><script><!--...</script></body></noframes></html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noframes>
+|       "<body><script><!--...</script></body>"
+|   <body>
+
+#data
+<textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (textarea).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "<!--<textarea>"
+|     "-->"
+
+#data
+<textarea>&lt;/textarea></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "</textarea>"
+
+#data
+<iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+Line: 1 Col: 41 Unexpected end tag (iframe).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "<!--<iframe>"
+|     "-->"
+
+#data
+<iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       "...<!--X->...<!--/X->..."
+
+#data
+<xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end tag (xmp).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+|       "<!--<xmp>"
+|     "-->"
+
+#data
+<noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE.
+Line: 1 Col: 45 Unexpected end tag (noembed).
+#document
+| <html>
+|   <head>
+|   <body>
+|     <noembed>
+|       "<!--<noembed>"
+|     "-->"
+
+#data
+<!doctype html><table>
+
+#errors
+Line 2 Col 0 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "
+"
+
+#data
+<!doctype html><table><td><span><font></span><span>
+#errors
+Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase.
+Line 1 Col 45 Unexpected end tag (span).
+Line 1 Col 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <span>
+|               <font>
+|             <font>
+|               <span>
+
+#data
+<!doctype html><form><table></form><form></table></form>
+#errors
+35: Stray end tag “form”.
+41: Start tag “form” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <table>
+|         <form>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests17.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests17.dat
new file mode 100644
index 0000000..7b555f8
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests17.dat
@@ -0,0 +1,153 @@
+#data
+<!doctype html><table><tbody><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><tr><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<!doctype html><table><tr><td><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <select>
+|           <td>
+
+#data
+<!doctype html><table><tr><th><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <th>
+|             <select>
+|           <td>
+
+#data
+<!doctype html><table><caption><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <select>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><th>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><tbody>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><thead>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><select><caption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><table><tr></table>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|     "a"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests18.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests18.dat
new file mode 100644
index 0000000..680e1f0
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests18.dat
@@ -0,0 +1,269 @@
+#data
+<!doctype html><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+
+#data
+<!doctype html><table><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+
+#data
+<!doctype html><table><tbody><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+|       <tbody>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><td><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <plaintext>
+|               "</plaintext>"
+
+#data
+<!doctype html><table><caption><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <plaintext>
+|           "</plaintext>"
+
+#data
+<!doctype html><table><tr><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "abc"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <style>
+|             "</script>"
+
+#data
+<!doctype html><table><tr><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "abc"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <script>
+|             "</style>"
+
+#data
+<!doctype html><table><caption><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <style>
+|           "</script>"
+|         "abc"
+
+#data
+<!doctype html><table><td><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <style>
+|               "</script>"
+|             "abc"
+
+#data
+<!doctype html><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <script>
+|         "</style>"
+|       "abc"
+
+#data
+<!doctype html><table><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <script>
+|         "</style>"
+|       "abc"
+|     <table>
+
+#data
+<!doctype html><table><tr><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <script>
+|         "</style>"
+|       "abc"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><frameset></frameset><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+
+#data
+<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+|   <!-- abc -->
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   <noframes>
+|     "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><table><tr></tbody><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|       <tfoot>
+
+#data
+<!doctype html><table><td><svg></svg>abc<td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|             "abc"
+|           <td>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests19.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests19.dat
new file mode 100644
index 0000000..0d62f5a
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests19.dat
@@ -0,0 +1,1237 @@
+#data
+<!doctype html><math><mn DefinitionUrl="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mn>
+|         definitionURL="foo"
+
+#data
+<!doctype html><html></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <!-- foo -->
+|   <head>
+|   <body>
+
+#data
+<!doctype html><head></head></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <!-- foo -->
+|   <body>
+
+#data
+<!doctype html><body><p><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <pre>
+
+#data
+<!doctype html><body><p><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <listing>
+
+#data
+<!doctype html><p><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <plaintext>
+
+#data
+<!doctype html><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <h1>
+
+#data
+<!doctype html><form><isindex>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+
+#data
+<!doctype html><isindex action="POST">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       action="POST"
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<!doctype html><isindex prompt="this is isindex">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "this is isindex"
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<!doctype html><isindex type="hidden">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|           type="hidden"
+|       <hr>
+
+#data
+<!doctype html><isindex name="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<!doctype html><ruby><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <p>
+|       <rp>
+
+#data
+<!doctype html><ruby><div><span><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <span>
+|           <rp>
+
+#data
+<!doctype html><ruby><div><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <p>
+|         <rp>
+
+#data
+<!doctype html><ruby><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <p>
+|       <rt>
+
+#data
+<!doctype html><ruby><div><span><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <span>
+|           <rt>
+
+#data
+<!doctype html><ruby><div><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <p>
+|         <rt>
+
+#data
+<!doctype html><math/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|     <foo>
+
+#data
+<!doctype html><svg/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <foo>
+
+#data
+<!doctype html><div></body><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|   <!-- foo -->
+
+#data
+<!doctype html><h1><div><h3><span></h1>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <h1>
+|       <div>
+|         <h3>
+|           <span>
+|         "foo"
+
+#data
+<!doctype html><p></h3>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "foo"
+
+#data
+<!doctype html><h3><li>abc</h2>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <h3>
+|       <li>
+|         "abc"
+|     "foo"
+
+#data
+<!doctype html><table>abc<!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "abc"
+|     <table>
+|       <!-- foo -->
+
+#data
+<!doctype html><table>  <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "  "
+|       <!-- foo -->
+
+#data
+<!doctype html><table> b <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     " b "
+|     <table>
+|       <!-- foo -->
+
+#data
+<!doctype html><select><option><option>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|       <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!doctype html><p><math><mi><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mi>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><mo><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mo>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><mn><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mn>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><ms><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math ms>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><p><math><mtext><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mtext>
+|           <p>
+|           <h1>
+
+#data
+<!doctype html><frameset></noframes>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html c=d><body></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   a="b"
+|   c="d"
+|   <head>
+|   <body>
+
+#data
+<!doctype html><html c=d><frameset></frameset></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   a="b"
+|   c="d"
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+| <!-- foo -->
+
+#data
+<!doctype html><html><frameset></frameset></html>  
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|   "  "
+
+#data
+<!doctype html><html><frameset></frameset></html>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<html><frameset></frameset></html><!doctype html>
+#errors
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!doctype html><p><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><p>a<frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "a"
+
+#data
+<!doctype html><p> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><pre><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+
+#data
+<!doctype html><listing><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <listing>
+
+#data
+<!doctype html><li><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <li>
+
+#data
+<!doctype html><dd><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <dd>
+
+#data
+<!doctype html><dt><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <dt>
+
+#data
+<!doctype html><button><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <button>
+
+#data
+<!doctype html><applet><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <applet>
+
+#data
+<!doctype html><marquee><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <marquee>
+
+#data
+<!doctype html><object><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <object>
+
+#data
+<!doctype html><table><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+
+#data
+<!doctype html><area><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <area>
+
+#data
+<!doctype html><basefont><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <basefont>
+|   <frameset>
+
+#data
+<!doctype html><bgsound><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <bgsound>
+|   <frameset>
+
+#data
+<!doctype html><br><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <br>
+
+#data
+<!doctype html><embed><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <embed>
+
+#data
+<!doctype html><img><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <img>
+
+#data
+<!doctype html><input><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+
+#data
+<!doctype html><keygen><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <keygen>
+
+#data
+<!doctype html><wbr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <wbr>
+
+#data
+<!doctype html><hr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <hr>
+
+#data
+<!doctype html><textarea></textarea><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+
+#data
+<!doctype html><xmp></xmp><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+
+#data
+<!doctype html><iframe></iframe><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+
+#data
+<!doctype html><select></select><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!doctype html><svg></svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><math></math><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><svg><foreignObject><div> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<!doctype html><svg>a</svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "a"
+
+#data
+<!doctype html><svg> </svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+|     <frame>
+
+#data
+<html>aaa<frameset></frameset>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "aaa"
+
+#data
+<html> a <frameset></frameset>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "a "
+
+#data
+<!doctype html><div><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><div><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<!doctype html><p><math></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|     "a"
+
+#data
+<!doctype html><p><math><mn><span></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <math math>
+|         <math mn>
+|           <span>
+|             <p>
+|             "a"
+
+#data
+<!doctype html><math></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+
+#data
+<!doctype html><meta charset="ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <meta>
+|       charset="ascii"
+|   <body>
+
+#data
+<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <meta>
+|       content="text/html;charset=ascii"
+|       http-equiv="content-type"
+|   <body>
+
+#data
+<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -->
+|     <meta>
+|       charset="utf8"
+|   <body>
+
+#data
+<!doctype html><html a=b><head></head><html c=d>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   a="b"
+|   c="d"
+|   <head>
+|   <body>
+
+#data
+<!doctype html><image/>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <img>
+
+#data
+<!doctype html>a<i>b<table>c<b>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "a"
+|     <i>
+|       "bc"
+|       <b>
+|         "de"
+|       "f"
+|       <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|     <div>
+|       <b>
+|         <i>
+|           "c"
+|           <a>
+|             "d"
+|         <a>
+|           "e"
+|       <a>
+|         "f"
+|     <table>
+
+#data
+<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|     <div>
+|       <b>
+|         <i>
+|           "c"
+|           <a>
+|             "d"
+|         <a>
+|           "e"
+|       <a>
+|         "f"
+
+#data
+<!doctype html><table><i>a<b>b<div>c</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|       <div>
+|         <i>
+|           "c"
+|     <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <b>
+|         "b"
+|     <b>
+|     <div>
+|       <b>
+|         <i>
+|           "c"
+|           <a>
+|             "d"
+|         <a>
+|           "e"
+|       <a>
+|         "f"
+|     <table>
+
+#data
+<!doctype html><table><i>a<div>b<tr>c<b>d</i>e
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <i>
+|       "a"
+|       <div>
+|         "b"
+|     <i>
+|       "c"
+|       <b>
+|         "d"
+|     <b>
+|       "e"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><table><td><table><i>a<div>b<b>c</i>d
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <i>
+|               "a"
+|             <div>
+|               <i>
+|                 "b"
+|                 <b>
+|                   "c"
+|               <b>
+|                 "d"
+|             <table>
+
+#data
+<!doctype html><body><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <bgsound>
+
+#data
+<!doctype html><body><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <basefont>
+
+#data
+<!doctype html><a><b></a><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <basefont>
+
+#data
+<!doctype html><a><b></a><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <bgsound>
+
+#data
+<!doctype html><figcaption><article></figcaption>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <figcaption>
+|       <article>
+|     "a"
+
+#data
+<!doctype html><summary><article></summary>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <summary>
+|       <article>
+|     "a"
+
+#data
+<!doctype html><p><a><plaintext>b
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <a>
+|     <plaintext>
+|       <a>
+|         "b"
+
+#data
+<!DOCTYPE html><div>a<a></div>b<p>c</p>d
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "a"
+|       <a>
+|     <a>
+|       "b"
+|       <p>
+|         "c"
+|       "d"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests2.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests2.dat
new file mode 100644
index 0000000..60d8592
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests2.dat
@@ -0,0 +1,763 @@
+#data
+<!DOCTYPE html>Test
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "Test"
+
+#data
+<textarea>test</div>test
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 24 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "test</div>test"
+
+#data
+<table><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 11 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><td>test</tbody></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "test"
+
+#data
+<frame>test
+#errors
+Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected start tag frame. Ignored.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "test"
+
+#data
+<!DOCTYPE html><frameset>test
+#errors
+Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><frameset><!DOCTYPE html>
+#errors
+Line: 1 Col: 40 Unexpected DOCTYPE. Ignored.
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><font><p><b>test</font>
+#errors
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|     <p>
+|       <font>
+|         <b>
+|           "test"
+
+#data
+<!DOCTYPE html><dt><div><dd>
+#errors
+Line: 1 Col: 28 Missing end tag (div, dt).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <dt>
+|       <div>
+|     <dd>
+
+#data
+<script></x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+|   <head>
+|     <script>
+|       "</x"
+|   <body>
+
+#data
+<table><plaintext><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "<td>"
+|     <table>
+
+#data
+<plaintext></plaintext>
+#errors
+Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <plaintext>
+|       "</plaintext>"
+
+#data
+<!DOCTYPE html><table><tr>TEST
+#errors
+Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "TEST"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>
+#errors
+Line: 1 Col: 37 Unexpected start tag (body).
+Line: 1 Col: 53 Unexpected start tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     t1="1"
+|     t2="2"
+|     t3="3"
+|     t4="4"
+
+#data
+</b test
+#errors
+Line: 1 Col: 8 Unexpected end of file in attribute name.
+Line: 1 Col: 8 End tag contains unexpected attributes.
+Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html></b test<b &=&amp>X
+#errors
+Line: 1 Col: 32 Named entity didn't end with ';'.
+Line: 1 Col: 33 End tag contains unexpected attributes.
+Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+
+#data
+<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 54 Unexpected end of file in the tag name.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       type="text/x-foobar;baz"
+|       "X</SCRipt"
+|   <body>
+
+#data
+&
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&"
+
+#data
+&#
+#errors
+Line: 1 Col: 1 Numeric entity expected. Got end of file instead.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&#"
+
+#data
+&#X
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&#X"
+
+#data
+&#x
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&#x"
+
+#data
+&#45
+#errors
+Line: 1 Col: 4 Numeric entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "-"
+
+#data
+&x-test
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&x-test"
+
+#data
+<!doctypehtml><p><li>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <li>
+
+#data
+<!doctypehtml><p><dt>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <dt>
+
+#data
+<!doctypehtml><p><dd>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <dd>
+
+#data
+<!doctypehtml><p><form>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <form>
+
+#data
+<!DOCTYPE html><p></P>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     "X"
+
+#data
+&AMP
+#errors
+Line: 1 Col: 4 Named entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&"
+
+#data
+&AMp;
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "&AMp;"
+
+#data
+<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>
+#errors
+Line: 1 Col: 110 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly>
+
+#data
+<!DOCTYPE html>X</body>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "XX"
+
+#data
+<!DOCTYPE html><!-- X
+#errors
+Line: 1 Col: 21 Unexpected end of file in comment.
+#document
+| <!DOCTYPE html>
+| <!--  X -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><table><caption>test TEST</caption><td>test
+#errors
+Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         "test TEST"
+|       <tbody>
+|         <tr>
+|           <td>
+|             "test"
+
+#data
+<!DOCTYPE html><select><option><optgroup>
+#errors
+Line: 1 Col: 41 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|       <optgroup>
+
+#data
+<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
+#errors
+Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 76 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <optgroup>
+|         <option>
+|       <option>
+|     <option>
+
+#data
+<!DOCTYPE html><select><optgroup><option><optgroup>
+#errors
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <optgroup>
+|         <option>
+|       <optgroup>
+
+#data
+<!DOCTYPE html><datalist><option>foo</datalist>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <datalist>
+|       <option>
+|         "foo"
+|     "bar"
+
+#data
+<!DOCTYPE html><font><input><input></font>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <input>
+|       <input>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!--  XXX - XXX  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX
+#errors
+Line: 1 Col: 29 Unexpected end of file in comment (-)
+#document
+| <!DOCTYPE html>
+| <!--  XXX - XXX -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!--  XXX - XXX - XXX  -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<isindex test=x name=x>
+#errors
+Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|           test="x"
+|       <hr>
+
+#data
+test
+test
+#errors
+Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "test
+test"
+
+#data
+<!DOCTYPE html><body><title>test</body></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "test</body>"
+
+#data
+<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>
+x { content:"</style" } </style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+|     <meta>
+|       name="z"
+|     <link>
+|       rel="foo"
+|     <style>
+|       "
+x { content:"</style" } "
+
+#data
+<!DOCTYPE html><select><optgroup></optgroup></select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <optgroup>
+
+#data
+ 
+ 
+#errors
+Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html>  <html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><script>
+</script>  <title>x</title>  </head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <script>
+|       "
+"
+|     "  "
+|     <title>
+|       "x"
+|     "  "
+|   <body>
+
+#data
+<!DOCTYPE html><html><body><html id=x>
+#errors
+Line: 1 Col: 38 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   id="x"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html>X</body><html id="x">
+#errors
+Line: 1 Col: 36 Unexpected start tag token (html) in the after body phase.
+Line: 1 Col: 36 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   id="x"
+|   <head>
+|   <body>
+|     "X"
+
+#data
+<!DOCTYPE html><head><html id=x>
+#errors
+Line: 1 Col: 32 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   id="x"
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html>X</html>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "XX"
+
+#data
+<!DOCTYPE html>X</html> 
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X "
+
+#data
+<!DOCTYPE html>X</html><p>X
+#errors
+Line: 1 Col: 26 Unexpected start tag (p).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <p>
+|       "X"
+
+#data
+<!DOCTYPE html>X<p/x/y/z>
+#errors
+Line: 1 Col: 19 Expected a > after the /.
+Line: 1 Col: 21 Solidus (/) incorrectly placed in tag.
+Line: 1 Col: 23 Solidus (/) incorrectly placed in tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <p>
+|       x=""
+|       y=""
+|       z=""
+
+#data
+<!DOCTYPE html><!--x--
+#errors
+Line: 1 Col: 22 Unexpected end of file in comment (--).
+#document
+| <!DOCTYPE html>
+| <!-- x -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE html><table><tr><td></p></table>
+#errors
+Line: 1 Col: 34 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <p>
+
+#data
+<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->
+#errors
+Line: 1 Col: 20 Expected space or '>'. Got ''
+Line: 1 Col: 25 Erroneous DOCTYPE.
+Line: 1 Col: 35 Unexpected character in comment found.
+#document
+| <!DOCTYPE <!doctype>
+| <html>
+|   <head>
+|   <body>
+|     ">"
+|     <!-- <!--x -->
+|     "-->"
+
+#data
+<!doctype html><div><form></form><div></div></div>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <form>
+|       <div>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests20.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests20.dat
new file mode 100644
index 0000000..6bd8256
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests20.dat
@@ -0,0 +1,455 @@
+#data
+<!doctype html><p><button><button>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|       <button>
+
+#data
+<!doctype html><p><button><address>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <address>
+
+#data
+<!doctype html><p><button><blockquote>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <blockquote>
+
+#data
+<!doctype html><p><button><menu>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <menu>
+
+#data
+<!doctype html><p><button><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <p>
+
+#data
+<!doctype html><p><button><ul>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <ul>
+
+#data
+<!doctype html><p><button><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <h1>
+
+#data
+<!doctype html><p><button><h6>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <h6>
+
+#data
+<!doctype html><p><button><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <listing>
+
+#data
+<!doctype html><p><button><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <pre>
+
+#data
+<!doctype html><p><button><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <form>
+
+#data
+<!doctype html><p><button><li>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <li>
+
+#data
+<!doctype html><p><button><dd>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <dd>
+
+#data
+<!doctype html><p><button><dt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <dt>
+
+#data
+<!doctype html><p><button><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <plaintext>
+
+#data
+<!doctype html><p><button><table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <table>
+
+#data
+<!doctype html><p><button><hr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <hr>
+
+#data
+<!doctype html><p><button><xmp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <xmp>
+
+#data
+<!doctype html><p><button></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <button>
+|         <p>
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <address>
+|       <button>
+|     "a"
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <address>
+|       <button>
+|     "a"
+
+#data
+<p><table></p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <p>
+|       <table>
+
+#data
+<!doctype html><svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<!doctype html><p><figcaption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <figcaption>
+
+#data
+<!doctype html><p><summary>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <summary>
+
+#data
+<!doctype html><form><table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <table>
+
+#data
+<!doctype html><table><form><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <form>
+
+#data
+<!doctype html><table><form></table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <form>
+
+#data
+<!doctype html><svg><foreignObject><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg foreignObject>
+|         <p>
+
+#data
+<!doctype html><svg><title>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         "abc"
+
+#data
+<option><span><option>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <option>
+|       <span>
+|         <option>
+
+#data
+<option><option>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <option>
+|     <option>
+
+#data
+<math><annotation-xml><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|     <div>
+
+#data
+<math><annotation-xml encoding="application/svg+xml"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="application/svg+xml"
+|     <div>
+
+#data
+<math><annotation-xml encoding="application/xhtml+xml"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="application/xhtml+xml"
+|         <div>
+
+#data
+<math><annotation-xml encoding="aPPlication/xhtmL+xMl"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="aPPlication/xhtmL+xMl"
+|         <div>
+
+#data
+<math><annotation-xml encoding="text/html"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="text/html"
+|         <div>
+
+#data
+<math><annotation-xml encoding="Text/htmL"><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding="Text/htmL"
+|         <div>
+
+#data
+<math><annotation-xml encoding=" text/html "><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         encoding=" text/html "
+|     <div>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests21.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests21.dat
new file mode 100644
index 0000000..1260ec0
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests21.dat
@@ -0,0 +1,221 @@
+#data
+<svg><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "foo"
+
+#data
+<math><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       "foo"
+
+#data
+<div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "foo"
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "foo"
+
+#data
+<svg><![CDATA[
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<svg><![CDATA[]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]] >"
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]] >"
+
+#data
+<svg><![CDATA[]]
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]]"
+
+#data
+<svg><![CDATA[]
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]"
+
+#data
+<svg><![CDATA[]>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "]>a"
+
+#data
+<svg><foreignObject><div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg foreignObject>
+|         <div>
+|           <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[<svg>]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+
+#data
+<svg><![CDATA[</svg>a]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "</svg>a"
+
+#data
+<svg><![CDATA[<svg>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>a"
+
+#data
+<svg><![CDATA[</svg>a
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "</svg>a"
+
+#data
+<svg><![CDATA[<svg>]]><path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+|       <svg path>
+
+#data
+<svg><![CDATA[<svg>]]></path>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+
+#data
+<svg><![CDATA[<svg>]]><!--path-->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>"
+|       <!-- path -->
+
+#data
+<svg><![CDATA[<svg>]]>path
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<svg>path"
+
+#data
+<svg><![CDATA[<!--svg-->]]>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       "<!--svg-->"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests22.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests22.dat
new file mode 100644
index 0000000..aab27b2
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests22.dat
@@ -0,0 +1,157 @@
+#data
+<a><b><big><em><strong><div>X</a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|         <big>
+|           <em>
+|             <strong>
+|     <big>
+|       <em>
+|         <strong>
+|           <div>
+|             <a>
+|               "X"
+
+#data
+<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>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <b>
+|       <div>
+|         id="1"
+|         <a>
+|         <div>
+|           id="2"
+|           <a>
+|           <div>
+|             id="3"
+|             <a>
+|             <div>
+|               id="4"
+|               <a>
+|               <div>
+|                 id="5"
+|                 <a>
+|                 <div>
+|                   id="6"
+|                   <a>
+|                   <div>
+|                     id="7"
+|                     <a>
+|                     <div>
+|                       id="8"
+|                       <a>
+|                         "A"
+
+#data
+<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>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <b>
+|       <div>
+|         id="1"
+|         <a>
+|         <div>
+|           id="2"
+|           <a>
+|           <div>
+|             id="3"
+|             <a>
+|             <div>
+|               id="4"
+|               <a>
+|               <div>
+|                 id="5"
+|                 <a>
+|                 <div>
+|                   id="6"
+|                   <a>
+|                   <div>
+|                     id="7"
+|                     <a>
+|                     <div>
+|                       id="8"
+|                       <a>
+|                         <div>
+|                           id="9"
+|                           "A"
+
+#data
+<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>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       <b>
+|     <b>
+|       <div>
+|         id="1"
+|         <a>
+|         <div>
+|           id="2"
+|           <a>
+|           <div>
+|             id="3"
+|             <a>
+|             <div>
+|               id="4"
+|               <a>
+|               <div>
+|                 id="5"
+|                 <a>
+|                 <div>
+|                   id="6"
+|                   <a>
+|                   <div>
+|                     id="7"
+|                     <a>
+|                     <div>
+|                       id="8"
+|                       <a>
+|                         <div>
+|                           id="9"
+|                           <div>
+|                             id="10"
+|                             "A"
+
+#data
+<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
+#errors
+Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE.
+Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <cite>
+|       <b>
+|         <cite>
+|           <i>
+|             <cite>
+|               <i>
+|                 <cite>
+|                   <i>
+|       <i>
+|         <i>
+|           <div>
+|             <b>
+|               "X"
+|             "TEST"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests23.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests23.dat
new file mode 100644
index 0000000..34d2a73
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests23.dat
@@ -0,0 +1,155 @@
+#data
+<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
+#errors
+3: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+116: Unclosed elements.
+117: End of file seen and there were open elements.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <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>
+|       <font>
+|         color="red"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|               <font>
+|                 color="red"
+|                 "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size="5"><font size=4><p>X
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="5"
+|               <font>
+|                 size="4"
+|     <p>
+|       <font>
+|         size="4"
+|         <font>
+|           size="4"
+|           <font>
+|             size="5"
+|             <font>
+|               size="4"
+|               "X"
+
+#data
+<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <font>
+|         id="a"
+|         size="4"
+|         <font>
+|           id="b"
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|     <p>
+|       <font>
+|         id="a"
+|         size="4"
+|         <font>
+|           id="b"
+|           size="4"
+|           <font>
+|             size="4"
+|             <font>
+|               size="4"
+|               "X"
+
+#data
+<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <b>
+|         id="a"
+|         <b>
+|           id="a"
+|           <b>
+|             id="a"
+|             <b>
+|               <object>
+|                 <b>
+|                   id="a"
+|                   <b>
+|                     id="a"
+|                     "X"
+|     <p>
+|       <b>
+|         id="a"
+|         <b>
+|           id="a"
+|           <b>
+|             id="a"
+|             <b>
+|               "Y"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests24.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests24.dat
new file mode 100644
index 0000000..f6dc7eb
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests24.dat
@@ -0,0 +1,79 @@
+#data
+<!DOCTYPE html>&NotEqualTilde;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "≂̸"
+
+#data
+<!DOCTYPE html>&NotEqualTilde;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "≂̸A"
+
+#data
+<!DOCTYPE html>&ThickSpace;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "  "
+
+#data
+<!DOCTYPE html>&ThickSpace;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "  A"
+
+#data
+<!DOCTYPE html>&NotSubset;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "⊂⃒"
+
+#data
+<!DOCTYPE html>&NotSubset;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "⊂⃒A"
+
+#data
+<!DOCTYPE html>&Gopf;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "𝔾"
+
+#data
+<!DOCTYPE html>&Gopf;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "𝔾A"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests25.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests25.dat
new file mode 100644
index 0000000..00de729
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests25.dat
@@ -0,0 +1,219 @@
+#data
+<!DOCTYPE html><body><foo>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       "A"
+
+#data
+<!DOCTYPE html><body><area>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <area>
+|     "A"
+
+#data
+<!DOCTYPE html><body><base>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <base>
+|     "A"
+
+#data
+<!DOCTYPE html><body><basefont>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <basefont>
+|     "A"
+
+#data
+<!DOCTYPE html><body><bgsound>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <bgsound>
+|     "A"
+
+#data
+<!DOCTYPE html><body><br>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <br>
+|     "A"
+
+#data
+<!DOCTYPE html><body><col>A
+#errors
+26: Stray start tag “col”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "A"
+
+#data
+<!DOCTYPE html><body><command>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <command>
+|     "A"
+
+#data
+<!DOCTYPE html><body><embed>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <embed>
+|     "A"
+
+#data
+<!DOCTYPE html><body><frame>A
+#errors
+26: Stray start tag “frame”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "A"
+
+#data
+<!DOCTYPE html><body><hr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <hr>
+|     "A"
+
+#data
+<!DOCTYPE html><body><img>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <img>
+|     "A"
+
+#data
+<!DOCTYPE html><body><input>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|     "A"
+
+#data
+<!DOCTYPE html><body><keygen>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <keygen>
+|     "A"
+
+#data
+<!DOCTYPE html><body><link>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <link>
+|     "A"
+
+#data
+<!DOCTYPE html><body><meta>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+|     "A"
+
+#data
+<!DOCTYPE html><body><param>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <param>
+|     "A"
+
+#data
+<!DOCTYPE html><body><source>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <source>
+|     "A"
+
+#data
+<!DOCTYPE html><body><track>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <track>
+|     "A"
+
+#data
+<!DOCTYPE html><body><wbr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <wbr>
+|     "A"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests26.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests26.dat
new file mode 100644
index 0000000..fae11ff
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests26.dat
@@ -0,0 +1,313 @@
+#data
+<!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>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       href="#1"
+|       <nobr>
+|         "1"
+|       <nobr>
+|     <nobr>
+|       <br>
+|       <a>
+|         href="#2"
+|     <a>
+|       href="#2"
+|       <nobr>
+|         "2"
+|       <nobr>
+|     <nobr>
+|       <br>
+|       <a>
+|         href="#3"
+|     <a>
+|       href="#3"
+|       <nobr>
+|         "3"
+|       <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|       <nobr>
+|     <nobr>
+|       <i>
+|     <i>
+|       <nobr>
+|         "2"
+|       <nobr>
+|     <nobr>
+|       "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|         <nobr>
+|           <i>
+|         <i>
+|           <nobr>
+|             "2"
+|           <nobr>
+|         <nobr>
+|           "3"
+|         <table>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|         <table>
+|           <tbody>
+|             <tr>
+|               <td>
+|                 <nobr>
+|                   <i>
+|                 <i>
+|                   <nobr>
+|                     "2"
+|                   <nobr>
+|                 <nobr>
+|                   "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|     <div>
+|       <b>
+|         <nobr>
+|         <nobr>
+|       <nobr>
+|         <i>
+|       <i>
+|         <nobr>
+|           "2"
+|         <nobr>
+|       <nobr>
+|         "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|       <nobr>
+|     <div>
+|       <nobr>
+|         <i>
+|       <i>
+|         <nobr>
+|           "2"
+|         <nobr>
+|       <nobr>
+|         "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|       <nobr>
+|         <ins>
+|     <nobr>
+|       <i>
+|     <i>
+|       <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       <nobr>
+|         "1"
+|         <ins>
+|       <nobr>
+|     <nobr>
+|       <i>
+|         "2"
+
+#data
+<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "1"
+|       <nobr>
+|     <nobr>
+|       <i>
+|     <i>
+|       <nobr>
+|         "2"
+
+#data
+<p><code x</code></p>
+
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <code>
+|         code=""
+|         x<=""
+|     <code>
+|       code=""
+|       x<=""
+|       "
+"
+
+#data
+<!DOCTYPE html><svg><foreignObject><p><i></p>a
+#errors
+45: End tag “p” seen, but there were open elements.
+41: Unclosed element “i”.
+46: End of file seen and there were open elements.
+35: Unclosed element “foreignObject”.
+20: Unclosed element “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg foreignObject>
+|         <p>
+|           <i>
+|         <i>
+|           "a"
+
+#data
+<!DOCTYPE html><table><tr><td><svg><foreignObject><p><i></p>a
+#errors
+56: End tag “p” seen, but there were open elements.
+52: Unclosed element “i”.
+57: End of file seen and there were open elements.
+46: Unclosed element “foreignObject”.
+31: Unclosed element “svg”.
+22: Unclosed element “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <svg svg>
+|               <svg foreignObject>
+|                 <p>
+|                   <i>
+|                 <i>
+|                   "a"
+
+#data
+<!DOCTYPE html><math><mtext><p><i></p>a
+#errors
+38: End tag “p” seen, but there were open elements.
+34: Unclosed element “i”.
+39: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mtext>
+|         <p>
+|           <i>
+|         <i>
+|           "a"
+
+#data
+<!DOCTYPE html><table><tr><td><math><mtext><p><i></p>a
+#errors
+53: End tag “p” seen, but there were open elements.
+49: Unclosed element “i”.
+54: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <math math>
+|               <math mtext>
+|                 <p>
+|                   <i>
+|                 <i>
+|                   "a"
+
+#data
+<!DOCTYPE html><body><div><!/div>a
+#errors
+29: Bogus comment.
+34: End of file seen and there were open elements.
+26: Unclosed element “div”.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <!-- /div -->
+|       "a"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests3.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests3.dat
new file mode 100644
index 0000000..38dc501
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests3.dat
@@ -0,0 +1,305 @@
+#data
+<head></head><style></style>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <style>
+|   <body>
+
+#data
+<head></head><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <script>
+|   <body>
+
+#data
+<head></head><!-- --><style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+|   <head>
+|     <style>
+|     <script>
+|   <!--   -->
+|   <!--   -->
+|   <body>
+
+#data
+<head></head><!-- -->x<style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <!--   -->
+|   <body>
+|     "x"
+|     <style>
+|     <!--   -->
+|     <script>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "foo
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x</pre><span>
+</span></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "x"
+|     <span>
+|       "
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x
+y</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "x
+y"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x<div>
+y</pre></body></html>
+#errors
+Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "x"
+|       <div>
+|         "
+y"
+
+#data
+<!DOCTYPE html><pre>&#x0a;&#x0a;A</pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <pre>
+|       "
+A"
+
+#data
+<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <meta>
+|   <body>
+
+#data
+<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<textarea>foo<span>bar</span><i>baz
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "foo<span>bar</span><i>baz"
+
+#data
+<title>foo<span>bar</em><i>baz
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "foo<span>bar</em><i>baz"
+|   <body>
+
+#data
+<!DOCTYPE html><textarea>
+</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+
+#data
+<!DOCTYPE html><textarea>
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "foo"
+
+#data
+<!DOCTYPE html><textarea>
+
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>
+#errors
+Line: 1 Col: 60 Missing end tag (div, li).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         <div>
+|           <p>
+|       <li>
+
+#data
+<!doctype html><nobr><nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <nobr>
+|     <nobr>
+|     <nobr>
+
+#data
+<!doctype html><nobr><nobr></nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <nobr>
+|     <nobr>
+|     <nobr>
+
+#data
+<!doctype html><html><body><p><table></table></body></html>
+#errors
+Not known
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <table>
+
+#data
+<p><table></table>
+#errors
+Not known
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <table>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests4.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests4.dat
new file mode 100644
index 0000000..3c50632
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests4.dat
@@ -0,0 +1,59 @@
+#data
+direct div content
+#errors
+#document-fragment
+div
+#document
+| "direct div content"
+
+#data
+direct textarea content
+#errors
+#document-fragment
+textarea
+#document
+| "direct textarea content"
+
+#data
+textarea content with <em>pseudo</em> <foo>markup
+#errors
+#document-fragment
+textarea
+#document
+| "textarea content with <em>pseudo</em> <foo>markup"
+
+#data
+this is &#x0043;DATA inside a <style> element
+#errors
+#document-fragment
+style
+#document
+| "this is &#x0043;DATA inside a <style> element"
+
+#data
+</plaintext>
+#errors
+#document-fragment
+plaintext
+#document
+| "</plaintext>"
+
+#data
+setting html's innerHTML
+#errors
+Line: 1 Col: 24 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+|   "setting html's innerHTML"
+
+#data
+<title>setting head's innerHTML</title>
+#errors
+#document-fragment
+head
+#document
+| <title>
+|   "setting head's innerHTML"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests5.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests5.dat
new file mode 100644
index 0000000..d7b5128
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests5.dat
@@ -0,0 +1,191 @@
+#data
+<style> <!-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!-- "
+|   <body>
+|     "x"
+
+#data
+<style> <!-- </style> --> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!-- "
+|     " "
+|   <body>
+|     "--> x"
+
+#data
+<style> <!--> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!--> "
+|   <body>
+|     "x"
+
+#data
+<style> <!---> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!---> "
+|   <body>
+|     "x"
+
+#data
+<iframe> <!---> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       " <!---> "
+|     "x"
+
+#data
+<iframe> <!--- </iframe>->x</iframe> --> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <iframe>
+|       " <!--- "
+|     "->x --> x"
+
+#data
+<script> <!-- </script> --> </script>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <script>
+|       " <!-- "
+|     " "
+|   <body>
+|     "--> x"
+
+#data
+<title> <!-- </title> --> </title>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       " <!-- "
+|     " "
+|   <body>
+|     "--> x"
+
+#data
+<textarea> <!--- </textarea>->x</textarea> --> </textarea>x
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <textarea>
+|       " <!--- "
+|     "->x --> x"
+
+#data
+<style> <!</-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <style>
+|       " <!</-- "
+|   <body>
+|     "x"
+
+#data
+<p><xmp></xmp>
+#errors
+XXX: Unknown
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|     <xmp>
+
+#data
+<xmp> <!-- > --> </xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <xmp>
+|       " <!-- > --> "
+
+#data
+<title>&amp;</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "&"
+|   <body>
+
+#data
+<title><!--&amp;--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<!--&-->"
+|   <body>
+
+#data
+<title><!--</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+|   <head>
+|     <title>
+|       "<!--"
+|   <body>
+
+#data
+<noscript><!--</noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|     <noscript>
+|       "<!--"
+|   <body>
+|     "-->"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests6.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests6.dat
new file mode 100644
index 0000000..f28ece4
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests6.dat
@@ -0,0 +1,663 @@
+#data
+<!doctype html></head> <head>
+#errors
+Line: 1 Col: 29 Unexpected start tag head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   " "
+|   <body>
+
+#data
+<!doctype html><form><div></form><div>
+#errors
+33: End tag "form" seen but there were unclosed elements.
+38: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <div>
+|         <div>
+
+#data
+<!doctype html><title>&amp;</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "&"
+|   <body>
+
+#data
+<!doctype html><title><!--&amp;--></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "<!--&-->"
+|   <body>
+
+#data
+<!doctype>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 10 Unexpected > character. Expected DOCTYPE name.
+Line: 1 Col: 10 Erroneous DOCTYPE.
+#document
+| <!DOCTYPE >
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!---x
+#errors
+Line: 1 Col: 6 Unexpected end of file in comment.
+Line: 1 Col: 6 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -x -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body>
+<div>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body).
+Line: 2 Col: 5 Expected closing tag. Unexpected end of file.
+#document-fragment
+div
+#document
+| "
+"
+| <div>
+
+#data
+<frameset></frameset>
+foo
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 3 Unexpected non-space characters in the after frameset phase. Ignored.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<frameset></frameset>
+<noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+|   <noframes>
+
+#data
+<frameset></frameset>
+<div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 5 Unexpected start tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<frameset></frameset>
+</html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<frameset></frameset>
+</div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 6 Unexpected end tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   "
+"
+
+#data
+<form><form>
+#errors
+Line: 1 Col: 6 Unexpected start tag (form). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (form).
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+
+#data
+<button><button>
+#errors
+Line: 1 Col: 8 Unexpected start tag (button). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (button) implies end tag (button).
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <button>
+|     <button>
+
+#data
+<table><tr><td></th>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (th). Ignored.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><caption><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (td). Ignored.
+Line: 1 Col: 20 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><caption><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <div>
+
+#data
+</caption><div>
+#errors
+Line: 1 Col: 10 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption><div></caption>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end tag (caption). Missing end tag (div).
+Line: 1 Col: 31 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <div>
+
+#data
+<table><caption></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+
+#data
+</table><div>
+#errors
+Line: 1 Col: 8 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 8 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (body). Ignored.
+Line: 1 Col: 29 Unexpected end tag (col). Ignored.
+Line: 1 Col: 40 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 47 Unexpected end tag (html). Ignored.
+Line: 1 Col: 55 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 60 Unexpected end tag (td). Ignored.
+Line: 1 Col: 68 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 73 Unexpected end tag (th). Ignored.
+Line: 1 Col: 81 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 86 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 86 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+
+#data
+<table><caption><div></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 27 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <div>
+
+#data
+<table><tr><td></body></caption></col></colgroup></html>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (body). Ignored.
+Line: 1 Col: 32 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 38 Unexpected end tag (col). Ignored.
+Line: 1 Col: 49 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 56 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+</table></tbody></tfoot></thead></tr><div>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 24 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 32 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 37 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document-fragment
+td
+#document
+| <div>
+
+#data
+<table><colgroup>foo
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "foo"
+|     <table>
+|       <colgroup>
+
+#data
+foo<col>
+#errors
+Line: 1 Col: 3 Unexpected end tag (colgroup). Ignored.
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<table><colgroup></col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 This element (col) has no end tag.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <colgroup>
+
+#data
+<frameset><div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</frameset><frame>
+#errors
+Line: 1 Col: 11 Unexpected end tag token (frameset) in the frameset phase (innerHTML).
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+<frameset></div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</body><div>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Ignored.
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document-fragment
+body
+#document
+| <div>
+
+#data
+<table><tr><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+</tr><td>
+#errors
+Line: 1 Col: 5 Unexpected end tag (tr). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</tbody></tfoot></thead><td>
+#errors
+Line: 1 Col: 8 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 24 Unexpected end tag (thead). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<table><tr><div><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected implied end tag (div) in the table row phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<caption><col><colgroup><tbody><tfoot><thead><tr>
+#errors
+Line: 1 Col: 9 Unexpected start tag (caption).
+Line: 1 Col: 14 Unexpected start tag (col).
+Line: 1 Col: 24 Unexpected start tag (colgroup).
+Line: 1 Col: 31 Unexpected start tag (tbody).
+Line: 1 Col: 38 Unexpected start tag (tfoot).
+Line: 1 Col: 45 Unexpected start tag (thead).
+Line: 1 Col: 49 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></thead>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (thead) in the table body phase. Ignored.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></body></caption></col></colgroup></html></td></th></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end tag (body) in the table body phase. Ignored.
+Line: 1 Col: 31 Unexpected end tag (caption) in the table body phase. Ignored.
+Line: 1 Col: 37 Unexpected end tag (col) in the table body phase. Ignored.
+Line: 1 Col: 48 Unexpected end tag (colgroup) in the table body phase. Ignored.
+Line: 1 Col: 55 Unexpected end tag (html) in the table body phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (td) in the table body phase. Ignored.
+Line: 1 Col: 65 Unexpected end tag (th) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end tag (tr) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+
+#data
+<table><tbody></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+
+#data
+<table><table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 14 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|     <table>
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end tag (body). Ignored.
+Line: 1 Col: 24 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 30 Unexpected end tag (col). Ignored.
+Line: 1 Col: 41 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 48 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 61 Unexpected end tag (td). Ignored.
+Line: 1 Col: 69 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 74 Unexpected end tag (th). Ignored.
+Line: 1 Col: 82 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 87 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 87 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+table
+#document
+| <tbody>
+|   <tr>
+
+#data
+<body></body></html>
+#errors
+Line: 1 Col: 20 Unexpected html end tag in inner html mode.
+Line: 1 Col: 20 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+
+#data
+<html><frameset></frameset></html> 
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <frameset>
+|   " "
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html>
+#errors
+Line: 1 Col: 50 Erroneous DOCTYPE.
+Line: 1 Col: 63 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "">
+| <html>
+|   <head>
+|   <body>
+
+#data
+<param><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (param). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<source><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (source). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<track><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (track). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</html><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+</body><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+|   <head>
+|   <frameset>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests7.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests7.dat
new file mode 100644
index 0000000..f5193c6
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests7.dat
@@ -0,0 +1,390 @@
+#data
+<!doctype html><body><title>X</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+
+#data
+<!doctype html><table><title>X</title></table>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) in table context caused voodoo mode.
+Line: 1 Col: 38 Unexpected end tag (title) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <title>
+|       "X"
+|     <table>
+
+#data
+<!doctype html><head></head><title>X</title>
+#errors
+Line: 1 Col: 35 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "X"
+|   <body>
+
+#data
+<!doctype html></head><title>X</title>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|     <title>
+|       "X"
+|   <body>
+
+#data
+<!doctype html><table><meta></table>
+#errors
+Line: 1 Col: 28 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <meta>
+|     <table>
+
+#data
+<!doctype html><table>X<tr><td><table> <meta></table></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 45 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <meta>
+|             <table>
+|               " "
+
+#data
+<!doctype html><html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!doctype html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!doctype html><table><style> <tr>x </style> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <style>
+|         " <tr>x "
+|       " "
+
+#data
+<!doctype html><table><TBODY><script> <tr>x </script> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <script>
+|           " <tr>x "
+|         " "
+
+#data
+<!doctype html><p><applet><p>X</p></applet>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <applet>
+|         <p>
+|           "X"
+
+#data
+<!doctype html><listing>
+X</listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <listing>
+|       "X"
+
+#data
+<!doctype html><select><input>X
+#errors
+Line: 1 Col: 30 Unexpected input start tag in the select phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <input>
+|     "X"
+
+#data
+<!doctype html><select><select>X
+#errors
+Line: 1 Col: 31 Unexpected select start tag in the select phase treated as select end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     "X"
+
+#data
+<!doctype html><table><input type=hidDEN></table>
+#errors
+Line: 1 Col: 41 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table>X<input type=hidDEN></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     "X"
+|     <table>
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table>  <input type=hidDEN></table>
+#errors
+Line: 1 Col: 43 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "  "
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table>  <input type='hidDEN'></table>
+#errors
+Line: 1 Col: 45 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       "  "
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table><input type=" hidden"><input type=hidDEN></table>
+#errors
+Line: 1 Col: 44 Unexpected start tag (input) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|       type=" hidden"
+|     <table>
+|       <input>
+|         type="hidDEN"
+
+#data
+<!doctype html><table><select>X<tr>
+#errors
+Line: 1 Col: 30 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 35 Unexpected table element start tag (trs) in the select in table phase.
+Line: 1 Col: 35 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "X"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!doctype html><select>X</select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "X"
+
+#data
+<!DOCTYPE hTmL><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<!DOCTYPE HTML><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+
+#data
+<body>X</body></body>
+#errors
+Line: 1 Col: 21 Unexpected end tag token (body) in the after body phase.
+Line: 1 Col: 21 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+|   "X"
+
+#data
+<div><p>a</x> b
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (x). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <p>
+|         "a b"
+
+#data
+<table><tr><td><code></code> </table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <code>
+|             " "
+
+#data
+<table><b><tr><td>aaa</td></tr>bbb</table>ccc
+#errors
+XXX: Fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <b>
+|       "bbb"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "aaa"
+|     <b>
+|       "ccc"
+
+#data
+A<table><tr> B</tr> B</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     "A B B"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+A<table><tr> B</tr> </em>C</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+|   <head>
+|   <body>
+|     "A BC"
+|     <table>
+|       <tbody>
+|         <tr>
+|         " "
+
+#data
+<select><keygen>
+#errors
+Not known
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|     <keygen>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests8.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests8.dat
new file mode 100644
index 0000000..90e6c91
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests8.dat
@@ -0,0 +1,148 @@
+#data
+<div>
+<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 3 Col: 7 Unexpected end tag (span). Ignored.
+Line: 3 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "
+"
+|       <div>
+|       "
+x"
+
+#data
+<div>x<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 2 Col: 7 Unexpected end tag (span). Ignored.
+Line: 2 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "
+x"
+
+#data
+<div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "xx"
+
+#data
+<div>x<div></div>y</span>z
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "yz"
+
+#data
+<table><div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 18 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 24 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span). Ignored.
+Line: 1 Col: 33 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "x"
+|       <div>
+|       "xx"
+|     <table>
+
+#data
+x<table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 9 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "xx"
+|     <table>
+
+#data
+x<table><table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 16 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <table>
+|     "x"
+|     <table>
+
+#data
+<b>a<div></div><div></b>y
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|       "a"
+|       <div>
+|     <div>
+|       <b>
+|       "y"
+
+#data
+<a><div><p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <div>
+|       <a>
+|       <p>
+|         <a>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests9.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests9.dat
new file mode 100644
index 0000000..554e27a
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests9.dat
@@ -0,0 +1,457 @@
+#data
+<!DOCTYPE html><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+
+#data
+<!DOCTYPE html><body><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+
+#data
+<!DOCTYPE html><math><mi>
+#errors
+25: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+
+#data
+<!DOCTYPE html><math><annotation-xml><svg><u>
+#errors
+45: HTML start tag “u” in a foreign namespace context.
+45: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math annotation-xml>
+|         <svg svg>
+|     <u>
+
+#data
+<!DOCTYPE html><body><select><math></math></select>
+#errors
+Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 42 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+
+#data
+<!DOCTYPE html><body><select><option><math></math></option></select>
+#errors
+Line: 1 Col: 43 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 50 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+
+#data
+<!DOCTYPE html><body><table><math></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>
+#errors
+Line: 1 Col: 41 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 72 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <table>
+|       <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>
+#errors
+Line: 1 Col: 45 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 57 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 69 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 76 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <math math>
+|               <math mi>
+|                 "foo"
+|               <math mi>
+|                 "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <math math>
+|               <math mi>
+|                 "foo"
+|               <math mi>
+|                 "bar"
+|             <p>
+|               "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <math math>
+|           <math mi>
+|             "foo"
+|           <math mi>
+|             "bar"
+|         <p>
+|           "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 70 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 81 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <math math>
+|           <math mi>
+|             "foo"
+|           <math mi>
+|             "bar"
+|         <p>
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux
+#errors
+Line: 1 Col: 78 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 78 Unexpected end tag (caption). Missing end tag (math).
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <caption>
+|         <math math>
+|           <math mi>
+|             "foo"
+|           <math mi>
+|             "bar"
+|           "baz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 44 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 56 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 68 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 71 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 71 Unexpected start tag (p) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <p>
+|       "baz"
+|     <table>
+|       <colgroup>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 50 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 62 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 74 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 77 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 88 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             <select>
+|               "foobarbaz"
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 36 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 42 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 80 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       "foobarbaz"
+|     <table>
+|     <p>
+|       "quux"
+
+#data
+<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 41 Unexpected start tag (math).
+Line: 1 Col: 68 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 34 Unexpected start tag token (math) in the after body phase.
+Line: 1 Col: 61 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mi>
+|         "foo"
+|       <math mi>
+|         "bar"
+|     <p>
+|       "baz"
+
+#data
+<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 31 Unexpected start tag token (math) in the frameset phase. Ignored.
+Line: 1 Col: 35 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 40 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 44 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 49 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 52 Unexpected start tag token (p) in the frameset phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (span) in the frameset phase. Ignored.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 42 Unexpected start tag (math) in the after frameset phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 51 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 55 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 63 Unexpected start tag (p) in the after frameset phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag (span) in the after frameset phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     <math math>
+|       xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <math math>
+|       <math mi>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <math math>
+|       <math mi>
+|         xlink href="foo"
+|         xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     xlink:href="foo"
+|     xml:lang="en"
+|     <math math>
+|       <math mi>
+|         xlink href="foo"
+|         xml lang="en"
+|       "bar"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tests_innerHTML_1.dat b/pkg/third_party/html5lib/test/data/tree-construction/tests_innerHTML_1.dat
new file mode 100644
index 0000000..6c78661
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tests_innerHTML_1.dat
@@ -0,0 +1,741 @@
+#data
+<body><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<body><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+|   <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <frameset>
+
+#data
+<table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+|   <tr>
+
+#data
+</table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+|   <tr>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a><caption>a
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <caption>
+|   "a"
+
+#data
+<a><colgroup><col>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <colgroup>
+|   <col>
+
+#data
+<a><tbody><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+
+#data
+<a><tfoot><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tfoot>
+|   <tr>
+
+#data
+<a><thead><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <thead>
+|   <tr>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+
+#data
+<a><th>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+|     <th>
+
+#data
+<a><td>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+|   <tr>
+|     <td>
+
+#data
+<table></table><tbody>
+#errors
+#document-fragment
+caption
+#document
+| <table>
+
+#data
+</table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></table>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+</caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><col><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><colgroup><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><html><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><tbody><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><td><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><tfoot><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><thead><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><th><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span><tr><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+<span></table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+|   <span>
+
+#data
+</colgroup><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<a><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+|   <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+|   <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+|   <td>
+
+#data
+<td><table><tbody><a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <tr>
+|   <td>
+|     <a>
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+</tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table><a><tr></tr><tr>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+|   <a>
+|   <table>
+|     <tbody>
+|       <tr>
+|       <tr>
+
+#data
+<caption><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<col><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<colgroup><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tbody><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tfoot><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<thead><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+|   <table>
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+|   <table>
+| <td>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</td><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<table><td><td>
+#errors
+#document-fragment
+td
+#document
+| <table>
+|   <tbody>
+|     <tr>
+|       <td>
+|       <td>
+
+#data
+</select><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<input><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<keygen><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<textarea><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+</html><!--abc-->
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <!-- abc -->
+
+#data
+</frameset><frame>
+#errors
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/tricky01.dat b/pkg/third_party/html5lib/test/data/tree-construction/tricky01.dat
new file mode 100644
index 0000000..0841992
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/tricky01.dat
@@ -0,0 +1,261 @@
+#data
+<b><p>Bold </b> Not bold</p>
+Also not bold.
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <b>
+|     <p>
+|       <b>
+|         "Bold "
+|       " Not bold"
+|     "
+Also not bold."
+
+#data
+<html>
+<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain
+<p>I should not be red. <font color=red>Red. <i>Italic and red.</p>
+<p>Italic and red. </i> Red.</font> I should not be red.</p>
+<b>Bold <i>Bold and italic</b> Only Italic </i> Plain
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       color="red"
+|       <i>
+|         "Italic and Red"
+|     <i>
+|       <p>
+|         <font>
+|           color="red"
+|           "Italic and Red "
+|         " Just italic."
+|       " Italic only."
+|     " Plain
+"
+|     <p>
+|       "I should not be red. "
+|       <font>
+|         color="red"
+|         "Red. "
+|         <i>
+|           "Italic and red."
+|     <font>
+|       color="red"
+|       <i>
+|         "
+"
+|     <p>
+|       <font>
+|         color="red"
+|         <i>
+|           "Italic and red. "
+|         " Red."
+|       " I should not be red."
+|     "
+"
+|     <b>
+|       "Bold "
+|       <i>
+|         "Bold and italic"
+|     <i>
+|       " Only Italic "
+|     " Plain"
+
+#data
+<html><body>
+<p><font size="7">First paragraph.</p>
+<p>Second paragraph.</p></font>
+<b><p><i>Bold and Italic</b> Italic</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "
+"
+|     <p>
+|       <font>
+|         size="7"
+|         "First paragraph."
+|     <font>
+|       size="7"
+|       "
+"
+|       <p>
+|         "Second paragraph."
+|     "
+"
+|     <b>
+|     <p>
+|       <b>
+|         <i>
+|           "Bold and Italic"
+|       <i>
+|         " Italic"
+
+#data
+<html>
+<dl>
+<dt><b>Boo
+<dd>Goo?
+</dl>
+</html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <dl>
+|       "
+"
+|       <dt>
+|         <b>
+|           "Boo
+"
+|       <dd>
+|         <b>
+|           "Goo?
+"
+|     <b>
+|       "
+"
+
+#data
+<html><body>
+<label><a><div>Hello<div>World</div></a></label>  
+</body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "
+"
+|     <label>
+|       <a>
+|       <div>
+|         <a>
+|           "Hello"
+|           <div>
+|             "World"
+|         "  
+"
+
+#data
+<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <center>
+|       " "
+|       <font>
+|         "a"
+|     <font>
+|       <img>
+|       " "
+|     <table>
+|       " "
+|       <tbody>
+|         <tr>
+|           <td>
+|             " "
+|           " "
+|         " "
+
+#data
+<table><tr><p><a><p>You should see this text.
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       <a>
+|     <p>
+|       <a>
+|         "You should see this text."
+|     <table>
+|       <tbody>
+|         <tr>
+
+#data
+<TABLE>
+<TR>
+<CENTER><CENTER><TD></TD></TR><TR>
+<FONT>
+<TABLE><tr></tr></TABLE>
+</P>
+<a></font><font></a>
+This page contains an insanely badly-nested tag sequence.
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <center>
+|       <center>
+|     <font>
+|       "
+"
+|     <table>
+|       "
+"
+|       <tbody>
+|         <tr>
+|           "
+"
+|           <td>
+|         <tr>
+|           "
+"
+|     <table>
+|       <tbody>
+|         <tr>
+|     <font>
+|       "
+"
+|       <p>
+|       "
+"
+|       <a>
+|     <a>
+|       <font>
+|     <font>
+|       "
+This page contains an insanely badly-nested tag sequence."
+
+#data
+<html>
+<body>
+<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
+nobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre>
+</body>
+</html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "
+"
+|     <b>
+|       <nobr>
+|     <div>
+|       <b>
+|         <nobr>
+|           "This text is in a div inside a nobr"
+|         "More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. "
+|       <pre>
+|         "A pre tag outside everything else."
+|       "
+
+"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/webkit01.dat b/pkg/third_party/html5lib/test/data/tree-construction/webkit01.dat
new file mode 100644
index 0000000..06bc436
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/webkit01.dat
@@ -0,0 +1,594 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+|   <head>
+|   <body>
+|     "Test"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+
+#data
+<div>Test</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "Test"
+
+#data
+<di
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<div>Hello</div>
+<script>
+console.log("PASS");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "Hello"
+|     "
+"
+|     <script>
+|       "
+console.log("PASS");
+"
+|     "
+"
+|     <div>
+|       "Bye"
+
+#data
+<div foo="bar">Hello</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo="bar"
+|       "Hello"
+
+#data
+<div>Hello</div>
+<script>
+console.log("FOO<span>BAR</span>BAZ");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       "Hello"
+|     "
+"
+|     <script>
+|       "
+console.log("FOO<span>BAR</span>BAZ");
+"
+|     "
+"
+|     <div>
+|       "Bye"
+
+#data
+<foo bar="baz"></foo><potato quack="duck"></potato>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       bar="baz"
+|     <potato>
+|       quack="duck"
+
+#data
+<foo bar="baz"><potato quack="duck"></potato></foo>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       bar="baz"
+|       <potato>
+|         quack="duck"
+
+#data
+<foo></foo bar="baz"><potato></potato quack="duck">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|     <potato>
+
+#data
+</ tttt>
+#errors
+#document
+| <!--  tttt -->
+| <html>
+|   <head>
+|   <body>
+
+#data
+<div FOO ><img><img></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       foo=""
+|       <img>
+|       <img>
+
+#data
+<p>Test</p<p>Test2</p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       "TestTest2"
+
+#data
+<rdar://problem/6869687>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <rdar:>
+|       6869687=""
+|       problem=""
+
+#data
+<A>test< /A>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|       "test< /A>"
+
+#data
+&lt;
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "<"
+
+#data
+<body foo='bar'><body foo='baz' yo='mama'>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     foo="bar"
+|     yo="mama"
+
+#data
+<body></br foo="bar"></body>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+
+#data
+<bdy><br foo="bar"></body>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <bdy>
+|       <br>
+|         foo="bar"
+
+#data
+<body></body></br foo="bar">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <br>
+
+#data
+<bdy></body><br foo="bar">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <bdy>
+|       <br>
+|         foo="bar"
+
+#data
+<html><body></body></html><!-- Hi there -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+| <!--  Hi there  -->
+
+#data
+<html><body></body></html>x<!-- Hi there -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <!--  Hi there  -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></html><!-- Again -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <!--  Hi there  -->
+| <!--  Again  -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></body></html><!-- Again -->
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "x"
+|     <!--  Hi there  -->
+| <!--  Again  -->
+
+#data
+<html><body><ruby><div><rp>xx</rp></div></ruby></body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <rp>
+|           "xx"
+
+#data
+<html><body><ruby><div><rt>xx</rt></div></ruby></body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ruby>
+|       <div>
+|         <rt>
+|           "xx"
+
+#data
+<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6-->
+#errors
+#document
+| <html>
+|   <head>
+|   <frameset>
+|     <!-- 1 -->
+|     <noframes>
+|       "A"
+|     <!-- 2 -->
+|   <!-- 3 -->
+|   <noframes>
+|     "B"
+|   <!-- 4 -->
+|   <noframes>
+|     "C"
+| <!-- 5 -->
+| <!-- 6 -->
+
+#data
+<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <select>
+|       <option>
+|         "A"
+|     <option>
+|       "B"
+|       <select>
+|         <option>
+|           "C"
+|     <option>
+|       "D"
+|       <select>
+|         <option>
+|           "E"
+|     <option>
+|       "F"
+|       <select>
+|         <option>
+|           "G"
+
+#data
+<dd><dd><dt><dt><dd><li><li>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <dd>
+|     <dd>
+|     <dt>
+|     <dt>
+|     <dd>
+|       <li>
+|       <li>
+
+#data
+<div><b></div><div><nobr>a<nobr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <b>
+|     <div>
+|       <b>
+|         <nobr>
+|           "a"
+|         <nobr>
+
+#data
+<head></head>
+<body></body>
+#errors
+#document
+| <html>
+|   <head>
+|   "
+"
+|   <body>
+
+#data
+<head></head> <style></style>ddd
+#errors
+#document
+| <html>
+|   <head>
+|     <style>
+|   " "
+|   <body>
+|     "ddd"
+
+#data
+<kbd><table></kbd><col><select><tr>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <kbd>
+|       <select>
+|       <table>
+|         <colgroup>
+|           <col>
+|         <tbody>
+|           <tr>
+
+#data
+<kbd><table></kbd><col><select><tr></table><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <kbd>
+|       <select>
+|       <table>
+|         <colgroup>
+|           <col>
+|         <tbody>
+|           <tr>
+|       <div>
+
+#data
+<a><li><style></style><title></title></a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <li>
+|       <a>
+|         <style>
+|         <title>
+
+#data
+<font></p><p><meta><title></title></font>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <font>
+|       <p>
+|     <p>
+|       <font>
+|         <meta>
+|         <title>
+
+#data
+<a><center><title></title><a>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <a>
+|     <center>
+|       <a>
+|         <title>
+|       <a>
+
+#data
+<svg><title><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         <div>
+
+#data
+<svg><title><rect><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         <rect>
+|           <div>
+
+#data
+<svg><title><svg><div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg title>
+|         <svg svg>
+|         <div>
+
+#data
+<img <="" FAIL>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <img>
+|       <=""
+|       fail=""
+
+#data
+<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <ul>
+|       <li>
+|         <div>
+|           id="foo"
+|           "A"
+|       <li>
+|         "B"
+|         <div>
+|           "C"
+
+#data
+<svg><em><desc></em>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|     <em>
+|       <desc>
+
+#data
+<svg><tfoot></mi><td>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <svg svg>
+|       <svg tfoot>
+|         <svg td>
+
+#data
+<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <math math>
+|       <math mrow>
+|         <math mrow>
+|           <math mn>
+|             "1"
+|         <math mi>
+|           "a"
+
+#data
+<!doctype html><input type="hidden"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <frameset>
+
+#data
+<!doctype html><input type="button"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+|   <head>
+|   <body>
+|     <input>
+|       type="button"
diff --git a/pkg/third_party/html5lib/test/data/tree-construction/webkit02.dat b/pkg/third_party/html5lib/test/data/tree-construction/webkit02.dat
new file mode 100644
index 0000000..468879b
--- /dev/null
+++ b/pkg/third_party/html5lib/test/data/tree-construction/webkit02.dat
@@ -0,0 +1,94 @@
+#data
+<foo bar=qux/>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <foo>
+|       bar="qux/"
+
+#data
+<p id="status"><noscript><strong>A</strong></noscript><span>B</span></p>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <p>
+|       id="status"
+|       <noscript>
+|         "<strong>A</strong>"
+|       <span>
+|         "B"
+
+#data
+<div><sarcasm><div></div></sarcasm></div>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <div>
+|       <sarcasm>
+|         <div>
+
+#data
+<html><body><img src="" border="0" alt="><div>A</div></body></html>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+
+#data
+<table><td></tbody>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     "A"
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+
+#data
+<table><td></thead>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "A"
+
+#data
+<table><td></tfoot>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <tbody>
+|         <tr>
+|           <td>
+|             "A"
+
+#data
+<table><thead><td></tbody>A
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <table>
+|       <thead>
+|         <tr>
+|           <td>
+|             "A"
diff --git a/pkg/third_party/html5lib/test/dom_compat_test.dart b/pkg/third_party/html5lib/test/dom_compat_test.dart
new file mode 100644
index 0000000..f95659b
--- /dev/null
+++ b/pkg/third_party/html5lib/test/dom_compat_test.dart
@@ -0,0 +1,31 @@
+library dom_compat_test;
+
+import 'dart:async';
+import 'dart:io';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/compact_vm_config.dart';
+import 'package:html5lib/dom.dart';
+
+part 'dom_compat_test_definitions.dart';
+
+main() {
+  useCompactVMConfiguration();
+
+  registerDomCompatTests();
+
+  test('content_shell', () {
+    _runDrt('test/browser/browser_test.html');
+  });
+}
+
+void _runDrt(String htmlFile) {
+  final allPassedRegExp = new RegExp('All \\d+ tests passed');
+
+  final future = Process.run('content_shell', ['--dump-render-tree', htmlFile])
+    .then((ProcessResult pr) {
+      expect(pr.exitCode, 0);
+      expect(pr.stdout, matches(allPassedRegExp), reason: pr.stdout);
+    });
+
+  expect(future, completion(isNull));
+}
diff --git a/pkg/third_party/html5lib/test/dom_compat_test_definitions.dart b/pkg/third_party/html5lib/test/dom_compat_test_definitions.dart
new file mode 100644
index 0000000..f1d83e7
--- /dev/null
+++ b/pkg/third_party/html5lib/test/dom_compat_test_definitions.dart
@@ -0,0 +1,10 @@
+part of dom_compat_test;
+
+void registerDomCompatTests() {
+  group('Element', () {
+    test('outerHtml', () {
+      final element = new Element.tag('div');
+      expect(element.outerHtml, '<div></div>');
+    });
+  });
+}
diff --git a/pkg/third_party/html5lib/test/dom_test.dart b/pkg/third_party/html5lib/test/dom_test.dart
new file mode 100644
index 0000000..8b339f0
--- /dev/null
+++ b/pkg/third_party/html5lib/test/dom_test.dart
@@ -0,0 +1,34 @@
+/** Additional feature tests that aren't based on test data. */
+library dom_test;
+
+import 'package:unittest/unittest.dart';
+import 'package:html5lib/parser.dart';
+import 'package:html5lib/dom.dart';
+
+main() {
+  group('Node.query type selectors', () {
+    test('x-foo', () {
+      expect(parse('<x-foo>').body.query('x-foo'), isNotNull);
+    });
+
+    test('-x-foo', () {
+      var doc = parse('<body><-x-foo>');
+      expect(doc.body.outerHtml, equals('<body>&lt;-x-foo&gt;</body>'));
+      expect(doc.body.query('-x-foo'), isNull);
+    });
+
+    test('foo123', () {
+      expect(parse('<foo123>').body.query('foo123'), isNotNull);
+    });
+
+    test('123 - invalid', () {
+      var doc = parse('<123>');
+      expect(() => doc.body.query('123'), throwsUnimplementedError);
+    });
+
+    test('x\\ny - not implemented', () {
+      var doc = parse('<x\\ny>');
+      expect(() => doc.body.query('x\\ny'), throwsUnimplementedError);
+    });
+  });
+}
diff --git a/pkg/third_party/html5lib/test/parser_feature_test.dart b/pkg/third_party/html5lib/test/parser_feature_test.dart
new file mode 100644
index 0000000..32269c3
--- /dev/null
+++ b/pkg/third_party/html5lib/test/parser_feature_test.dart
@@ -0,0 +1,251 @@
+/** Additional feature tests that aren't based on test data. */
+library parser_feature_test;
+
+import 'package:unittest/unittest.dart';
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/dom_parsing.dart';
+import 'package:html5lib/parser.dart';
+import 'package:html5lib/src/constants.dart';
+import 'package:html5lib/src/tokenizer.dart';
+import 'package:html5lib/src/treebuilder.dart';
+
+main() {
+  test('doctype is cloneable', () {
+    var doc = parse('<!DOCTYPE HTML>');
+    DocumentType doctype = doc.nodes[0];
+    expect(doctype.clone().outerHtml, '<!DOCTYPE html>');
+  });
+
+  test('line counter', () {
+    // http://groups.google.com/group/html5lib-discuss/browse_frm/thread/f4f00e4a2f26d5c0
+    var doc = parse("<pre>\nx\n&gt;\n</pre>");
+    expect(doc.body.innerHtml, "<pre>x\n&gt;\n</pre>");
+  });
+
+  test('namespace html elements on', () {
+    var doc = new HtmlParser('', tree: new TreeBuilder(true)).parse();
+    expect(doc.nodes[0].namespace, Namespaces.html);
+  });
+
+  test('namespace html elements off', () {
+    var doc = new HtmlParser('', tree: new TreeBuilder(false)).parse();
+    expect(doc.nodes[0].namespace, null);
+  });
+
+  test('parse error spans - full', () {
+    var parser = new HtmlParser('''
+<!DOCTYPE html>
+<html>
+  <body>
+  <!DOCTYPE html>
+  </body>
+</html>
+''', generateSpans: true, sourceUrl: 'ParseError');
+    var doc = parser.parse();
+    expect(doc.body.outerHtml, '<body>\n  \n  \n\n</body>');
+    expect(parser.errors.length, 1);
+    ParseError error = parser.errors[0];
+    expect(error.errorCode, 'unexpected-doctype');
+
+    // Note: these values are 0-based, but the printed format is 1-based.
+    expect(error.span.start.line, 3);
+    expect(error.span.end.line, 3);
+    expect(error.span.start.column, 2);
+    expect(error.span.end.column, 17);
+    expect(error.span.text, '<!DOCTYPE html>');
+
+    expect(error.toString(), '''
+ParseError:4:3: Unexpected DOCTYPE. Ignored.
+  <!DOCTYPE html>
+  ^^^^^^^^^^^^^^^''');
+  });
+
+  test('parse error spans - minimal', () {
+    var parser = new HtmlParser('''
+<!DOCTYPE html>
+<html>
+  <body>
+  <!DOCTYPE html>
+  </body>
+</html>
+''');
+    var doc = parser.parse();
+    expect(doc.body.outerHtml, '<body>\n  \n  \n\n</body>');
+    expect(parser.errors.length, 1);
+    ParseError error = parser.errors[0];
+    expect(error.errorCode, 'unexpected-doctype');
+    expect(error.span.start.line, 3);
+    // Note: error position is at the end, not the beginning
+    expect(error.span.start.column, 17);
+  });
+
+  test('text spans should have the correct length', () {
+    var textContent = '\n  hello {{name}}';
+    var html = '<body><div>$textContent</div>';
+    var doc = parse(html, generateSpans: true);
+    var text = doc.body.nodes[0].nodes[0];
+    expect(text, new isInstanceOf<Text>());
+    expect(text.value, textContent);
+    expect(text.sourceSpan.start.offset, html.indexOf(textContent));
+    expect(text.sourceSpan.length, textContent.length);
+  });
+
+  test('attribute spans', () {
+    var text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
+    var doc = parse(text, generateSpans: true);
+    var elem = doc.query('element');
+    expect(elem.sourceSpan.start.offset, 0);
+    expect(elem.sourceSpan.end.offset, text.length);
+    expect(elem.sourceSpan.text, text);
+
+    expect(elem.attributeSpans['quux'], null);
+
+    var span = elem.attributeSpans['extends'];
+    expect(span.start.offset, text.indexOf('extends'));
+    expect(span.text, 'extends="x-bar"');
+  });
+
+  test('attribute value spans', () {
+    var text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
+    var doc = parse(text, generateSpans: true);
+    var elem = doc.query('element');
+
+    expect(elem.attributeValueSpans['quux'], null);
+
+    var span = elem.attributeValueSpans['extends'];
+    expect(span.start.offset, text.indexOf('x-bar'));
+    expect(span.text, 'x-bar');
+  });
+
+  test('attribute spans if no attributes', () {
+    var text = '<element>';
+    var doc = parse(text, generateSpans: true);
+    var elem = doc.query('element');
+
+    expect(elem.attributeSpans['quux'], null);
+    expect(elem.attributeValueSpans['quux'], null);
+  });
+
+  test('attribute spans if no attribute value', () {
+    var text = '<foo template>';
+    var doc = parse(text, generateSpans: true);
+    var elem = doc.query('foo');
+
+    expect(elem.attributeSpans['template'].start.offset,
+        text.indexOf('template'));
+    expect(elem.attributeValueSpans.containsKey('template'), false);
+  });
+
+  test('attribute spans null if code parsed without spans', () {
+    var text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
+    var doc = parse(text);
+    var elem = doc.query('element');
+    expect(elem.sourceSpan, null);
+    expect(elem.attributeSpans['quux'], null);
+    expect(elem.attributeSpans['extends'], null);
+  });
+
+  test('void element innerHTML', () {
+    var doc = parse('<div></div>');
+    expect(doc.body.innerHtml, '<div></div>');
+    doc = parse('<body><script></script></body>');
+    expect(doc.body.innerHtml, '<script></script>');
+    doc = parse('<br>');
+    expect(doc.body.innerHtml, '<br>');
+    doc = parse('<br><foo><bar>');
+    expect(doc.body.innerHtml, '<br><foo><bar></bar></foo>');
+  });
+
+  test('empty document has html, body, and head', () {
+    var doc = parse('');
+    expect(doc.outerHtml, '<html><head></head><body></body></html>');
+    expect(doc.head.outerHtml, '<head></head>');
+    expect(doc.body.outerHtml, '<body></body>');
+  });
+
+  test('strange table case', () {
+    var doc = parseFragment('<table><tbody><foo>');
+    expect(doc.outerHtml, '<foo></foo><table><tbody></tbody></table>');
+  });
+
+  group('html serialization', () {
+    test('attribute order', () {
+      // Note: the spec only requires a stable order.
+      // However, we preserve the input order via LinkedHashMap
+      var doc = parseFragment('<foo d=1 a=2 c=3 b=4>');
+      expect(doc.outerHtml, '<foo d="1" a="2" c="3" b="4"></foo>');
+      expect(doc.query('foo').attributes.remove('a'), '2');
+      expect(doc.outerHtml, '<foo d="1" c="3" b="4"></foo>');
+      doc.query('foo').attributes['a'] = '0';
+      expect(doc.outerHtml, '<foo d="1" c="3" b="4" a="0"></foo>');
+    });
+
+    test('escaping Text node in <script>', () {
+      var doc = parseFragment('<script>a && b</script>');
+      expect(doc.outerHtml, '<script>a && b</script>');
+    });
+
+    test('escaping Text node in <span>', () {
+      var doc = parseFragment('<span>a && b</span>');
+      expect(doc.outerHtml, '<span>a &amp;&amp; b</span>');
+    });
+
+    test('Escaping attributes', () {
+      var doc = parseFragment('<div class="a<b>">');
+      expect(doc.outerHtml, '<div class="a<b>"></div>');
+      doc = parseFragment('<div class=\'a"b\'>');
+      expect(doc.outerHtml, '<div class="a&quot;b"></div>');
+    });
+
+    test('Escaping non-breaking space', () {
+      var text = '<span>foO\u00A0bar</span>';
+      expect(text.codeUnitAt(text.indexOf('O') + 1), 0xA0);
+      var doc = parseFragment(text);
+      expect(doc.outerHtml, '<span>foO&nbsp;bar</span>');
+    });
+
+    test('Newline after <pre>', () {
+      var doc = parseFragment('<pre>\n\nsome text</span>');
+      expect(doc.query('pre').nodes[0].value, '\nsome text');
+      expect(doc.outerHtml, '<pre>\n\nsome text</pre>');
+
+      doc = parseFragment('<pre>\nsome text</span>');
+      expect(doc.query('pre').nodes[0].value, 'some text');
+      expect(doc.outerHtml, '<pre>some text</pre>');
+    });
+
+    test('xml namespaces', () {
+      // Note: this is a nonsensical example, but it triggers the behavior
+      // we're looking for with attribute names in foreign content.
+      var doc = parse('''
+        <body>
+        <svg>
+        <desc xlink:type="simple"
+              xlink:href="http://example.com/logo.png"
+              xlink:show="new"></desc>
+      ''');
+      var n = doc.query('desc');
+      var keys = n.attributes.keys.toList();
+      expect(keys[0], new isInstanceOf<AttributeName>());
+      expect(keys[0].prefix, 'xlink');
+      expect(keys[0].namespace, 'http://www.w3.org/1999/xlink');
+      expect(keys[0].name, 'type');
+
+      expect(n.outerHtml, '<desc xlink:type="simple" '
+          'xlink:href="http://example.com/logo.png" xlink:show="new"></desc>');
+    });
+  });
+
+  test('error printing without spans', () {
+    var parser = new HtmlParser('foo');
+    var doc = parser.parse();
+    expect(doc.body.innerHtml, 'foo');
+    expect(parser.errors.length, 1);
+    expect(parser.errors[0].errorCode, 'expected-doctype-but-got-chars');
+    expect(parser.errors[0].message,
+        'Unexpected non-space characters. Expected DOCTYPE.');
+    expect(parser.errors[0].toString(),
+        'ParserError:1:4: Unexpected non-space characters. '
+        'Expected DOCTYPE.');
+  });
+}
diff --git a/pkg/third_party/html5lib/test/parser_test.dart b/pkg/third_party/html5lib/test/parser_test.dart
new file mode 100644
index 0000000..0125634
--- /dev/null
+++ b/pkg/third_party/html5lib/test/parser_test.dart
@@ -0,0 +1,124 @@
+library parser_test;
+
+import 'dart:io';
+import 'dart:json' as json;
+import 'package:path/path.dart' as pathos;
+import 'package:unittest/unittest.dart';
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/parser.dart';
+import 'package:html5lib/parser_console.dart' as parser_console;
+import 'package:html5lib/src/constants.dart';
+import 'package:html5lib/src/inputstream.dart' as inputstream;
+import 'package:html5lib/src/tokenizer.dart';
+import 'package:html5lib/src/utils.dart';
+import 'support.dart';
+
+// Run the parse error checks
+// TODO(jmesserly): presumably we want this on by default?
+final checkParseErrors = false;
+
+String namespaceHtml(String expected) {
+  // TODO(jmesserly): this is a workaround for http://dartbug.com/2979
+  // We can't do regex replace directly =\
+  // final namespaceExpected = new RegExp(@"^(\s*)<(\S+)>", multiLine: true);
+  // return expected.replaceAll(namespaceExpected, @"$1<html $2>");
+  final namespaceExpected = new RegExp(r"^(\|\s*)<(\S+)>");
+  var lines =  expected.split("\n");
+  for (int i = 0; i < lines.length; i++) {
+    var match = namespaceExpected.firstMatch(lines[i]);
+    if (match != null) {
+      lines[i] = "${match[1]}<html ${match[2]}>";
+    }
+  }
+  return lines.join("\n");
+}
+
+void runParserTest(String groupName, String innerHTML, String input,
+    String expected, List errors, TreeBuilderFactory treeCtor,
+    bool namespaceHTMLElements) {
+
+  // XXX - move this out into the setup function
+  // concatenate all consecutive character tokens into a single token
+  var builder = treeCtor(namespaceHTMLElements);
+  var parser = new HtmlParser(input, tree: builder);
+
+  Node document;
+  if (innerHTML != null) {
+    document = parser.parseFragment(innerHTML);
+  } else {
+    document = parser.parse();
+  }
+
+  var output = testSerializer(document);
+
+  if (namespaceHTMLElements) {
+    expected = namespaceHtml(expected);
+  }
+
+  expect(output, equals(expected), reason:
+      "\n\nInput:\n$input\n\nExpected:\n$expected\n\nReceived:\n$output");
+
+  if (checkParseErrors) {
+    expect(parser.errors.length, equals(errors.length), reason:
+        "\n\nInput:\n$input\n\nExpected errors (${errors.length}):\n"
+        "${errors.join('\n')}\n\n"
+        "Actual errors (${parser.errors.length}):\n"
+        "${parser.errors.map((e) => '$e').join('\n')}");
+  }
+}
+
+
+void main() {
+
+  test('dart:io', () {
+    // ensure IO support is unregistered
+    expect(inputstream.consoleSupport,
+        new isInstanceOf<inputstream.ConsoleSupport>());
+    var file = new File('$testDataDir/parser_feature/raw_file.html').openSync();
+    expect(() => parse(file), throwsA(new isInstanceOf<ArgumentError>()));
+    parser_console.useConsole();
+    expect(parse(file).body.innerHtml.trim(), 'Hello world!');
+  });
+
+  for (var path in getDataFiles('tree-construction')) {
+    if (!path.endsWith('.dat')) continue;
+
+    var tests = new TestData(path, "data");
+    var testName = pathos.basenameWithoutExtension(path);
+
+    group(testName, () {
+      int index = 0;
+      for (var testData in tests) {
+        var input = testData['data'];
+        var errors = testData['errors'];
+        var innerHTML = testData['document-fragment'];
+        var expected = testData['document'];
+        if (errors != null) {
+          errors = errors.split("\n");
+        }
+
+        for (var treeCtor in treeTypes.values) {
+          for (var namespaceHTMLElements in const [false, true]) {
+            test(_nameFor(input), () {
+              runParserTest(testName, innerHTML, input, expected, errors,
+                  treeCtor, namespaceHTMLElements);
+            });
+          }
+        }
+
+        index++;
+      }
+    });
+  }
+}
+
+/** Extract the name for the test based on the test input data. */
+_nameFor(String input) {
+  // Using json.parse to unescape other unicode characters
+  var escapeQuote = input
+      .replaceAll(new RegExp('\\\\.'), '_')
+      .replaceAll(new RegExp('\u0000'), '_')
+      .replaceAll('"', '\\"')
+      .replaceAll(new RegExp('[\n\r\t]'),'_');
+  return json.parse('"$escapeQuote"');
+}
diff --git a/pkg/third_party/html5lib/test/run.sh b/pkg/third_party/html5lib/test/run.sh
new file mode 100755
index 0000000..f269bda
--- /dev/null
+++ b/pkg/third_party/html5lib/test/run.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# Copyright (c) 2012, the Dart project authors.  Please see the LICENSE file
+# for details. All rights reserved. Use of this source code is governed by a
+# MIT-style license that can be found in the LICENSE file.
+
+# bail on error
+set -e
+
+# TODO(sigmund): replace with a real test runner
+DIR=$( cd $( dirname "${BASH_SOURCE[0]}" ) && pwd )
+
+# Note: dart_analyzer needs to be run from the root directory for proper path
+# canonicalization.
+pushd $DIR/..
+# TODO(jmesserly): switch to new analyzer. Note: it's missing a lot of the
+# tests for implemented members; we should get that fixed before switching.
+echo Analyzing library for warnings or type errors
+dartanalyzer --fatal-warnings --fatal-type-errors lib/*.dart || \
+  echo "ignore analyzer errors"
+popd
+
+dart --enable-type-checks --enable-asserts test/run_all.dart $@
diff --git a/pkg/third_party/html5lib/test/run_all.dart b/pkg/third_party/html5lib/test/run_all.dart
new file mode 100644
index 0000000..dcff524
--- /dev/null
+++ b/pkg/third_party/html5lib/test/run_all.dart
@@ -0,0 +1,34 @@
+#!/usr/bin/env dart
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.run_all;
+
+import 'dart:io' show Options;
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+
+import 'dom_test.dart' as dom_test;
+import 'parser_feature_test.dart' as parser_feature_test;
+import 'parser_test.dart' as parser_test;
+import 'tokenizer_test.dart' as tokenizer_test;
+import 'dom_compat_test.dart' as dom_compat_test;
+
+main() {
+  var args = new Options().arguments;
+  var pattern = new RegExp(args.length > 0 ? args[0] : '.');
+  useCompactVMConfiguration();
+
+  void addGroup(testFile, testMain) {
+    if (pattern.hasMatch(testFile)) {
+      group(testFile.replaceAll('_test.dart', ':'), testMain);
+    }
+  }
+
+  addGroup('dom_test.dart', dom_test.main);
+  addGroup('dom_compat_test.dart', dom_compat_test.main);
+  addGroup('parser_feature_test.dart', parser_feature_test.main);
+  addGroup('parser_test.dart', parser_test.main);
+  addGroup('tokenizer_test.dart', tokenizer_test.main);
+}
diff --git a/pkg/third_party/html5lib/test/support.dart b/pkg/third_party/html5lib/test/support.dart
new file mode 100644
index 0000000..c879bf8
--- /dev/null
+++ b/pkg/third_party/html5lib/test/support.dart
@@ -0,0 +1,168 @@
+/** Support code for the tests in this directory. */
+library support;
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:collection';
+import 'package:path/path.dart' as path;
+import 'package:html5lib/src/treebuilder.dart';
+import 'package:html5lib/dom.dart';
+import 'package:html5lib/dom_parsing.dart';
+
+typedef TreeBuilder TreeBuilderFactory(bool namespaceHTMLElements);
+
+Map _treeTypes;
+Map<String, TreeBuilderFactory> get treeTypes {
+  if (_treeTypes == null) {
+    // TODO(jmesserly): add DOM here once it's implemented
+    _treeTypes = { "simpletree": (useNs) => new TreeBuilder(useNs) };
+  }
+  return _treeTypes;
+}
+
+final testDataDir = path.join(path.dirname(new Options().script), 'data');
+
+Iterable<String> getDataFiles(String subdirectory) {
+  var dir = new Directory(path.join(testDataDir, subdirectory));
+  return dir.listSync().where((f) => f is File).map((f) => f.path);
+}
+
+// TODO(jmesserly): make this class simpler. We could probably split on
+// "\n#" instead of newline and remove a lot of code.
+class TestData extends IterableBase<Map> {
+  final String _text;
+  final String newTestHeading;
+
+  TestData(String filename, [this.newTestHeading = "data"])
+      // Note: can't use readAsLinesSync here because it splits on \r
+      : _text = new File(filename).readAsStringSync();
+
+  // Note: in Python this was a generator, but since we can't do that in Dart,
+  // it's easier to convert it into an upfront computation.
+  Iterator<Map> get iterator => _getData().iterator;
+
+  List<Map> _getData() {
+    var data = <String, String>{};
+    var key = null;
+    var result = <Map>[];
+    var lines = _text.split('\n');
+    int numLines = lines.length;
+    // Remove trailing newline to match Python
+    if (lines.last == '') {
+      lines.removeLast();
+    }
+    for (var line in lines) {
+      var heading = sectionHeading(line);
+      if (heading != null) {
+        if (data.length > 0 && heading == newTestHeading) {
+          // Remove trailing newline
+          data[key] = data[key].substring(0, data[key].length - 1);
+          result.add(normaliseOutput(data));
+          data = <String, String>{};
+        }
+        key = heading;
+        data[key] = "";
+      } else if (key != null) {
+        data[key] = '${data[key]}$line\n';
+      }
+    }
+
+    if (data.length > 0) {
+      result.add(normaliseOutput(data));
+    }
+    return result;
+  }
+
+  /**
+   * If the current heading is a test section heading return the heading,
+   * otherwise return null.
+   */
+  static String sectionHeading(String line) {
+    return line.startsWith("#") ? line.substring(1).trim() : null;
+  }
+
+  static Map normaliseOutput(Map data) {
+    // Remove trailing newlines
+    data.forEach((key, value) {
+      if (value.endsWith("\n")) {
+        data[key] = value.substring(0, value.length - 1);
+      }
+    });
+    return data;
+  }
+}
+
+/**
+ * Serialize the [document] into the html5 test data format.
+ */
+testSerializer(Document document) {
+  return (new TestSerializer()..visit(document)).toString();
+}
+
+/** Serializes the DOM into test format. See [testSerializer]. */
+class TestSerializer extends TreeVisitor {
+  final StringBuffer _str;
+  int _indent = 0;
+  String _spaces = '';
+
+  TestSerializer() : _str = new StringBuffer();
+
+  String toString() => _str.toString();
+
+  int get indent => _indent;
+
+  set indent(int value) {
+    if (_indent == value) return;
+
+    var arr = new List<int>(value);
+    for (int i = 0; i < value; i++) {
+      arr[i] = 32;
+    }
+    _spaces = new String.fromCharCodes(arr);
+    _indent = value;
+  }
+
+  void _newline() {
+    if (_str.length > 0) _str.write('\n');
+    _str.write('|$_spaces');
+  }
+
+  visitNodeFallback(Node node) {
+    _newline();
+    _str.write(node);
+    visitChildren(node);
+  }
+
+  visitChildren(Node node) {
+    indent += 2;
+    for (var child in node.nodes) visit(child);
+    indent -= 2;
+  }
+
+  visitDocument(Document node) {
+    indent += 1;
+    for (var child in node.nodes) visit(child);
+    indent -= 1;
+  }
+
+  visitElement(Element node) {
+    _newline();
+    _str.write(node);
+    if (node.attributes.length > 0) {
+      indent += 2;
+      var keys = new List.from(node.attributes.keys);
+      keys.sort((x, y) => x.compareTo(y));
+      for (var key in keys) {
+        var v = node.attributes[key];
+        if (key is AttributeName) {
+          AttributeName attr = key;
+          key = "${attr.prefix} ${attr.name}";
+        }
+        _newline();
+        _str.write('$key="$v"');
+      }
+      indent -= 2;
+    }
+    visitChildren(node);
+  }
+}
diff --git a/pkg/third_party/html5lib/test/tokenizer_test.dart b/pkg/third_party/html5lib/test/tokenizer_test.dart
new file mode 100644
index 0000000..fc98012
--- /dev/null
+++ b/pkg/third_party/html5lib/test/tokenizer_test.dart
@@ -0,0 +1,270 @@
+library tokenizer_test;
+
+// Note: mirrors used to match the getattr usage in the original test
+import 'dart:async';
+import 'dart:io';
+import 'dart:json' as json;
+import 'dart:mirrors';
+import 'dart:utf';
+import 'package:path/path.dart' as pathos;
+import 'package:unittest/unittest.dart';
+import 'package:html5lib/src/char_encodings.dart';
+import 'package:html5lib/src/constants.dart' as constants;
+import 'package:html5lib/src/token.dart';
+import 'package:html5lib/src/tokenizer.dart';
+import 'package:html5lib/src/utils.dart';
+import 'support.dart';
+
+class TokenizerTestParser {
+  String _state;
+  var _lastStartTag;
+  List outputTokens;
+
+  TokenizerTestParser(String initialState, [lastStartTag])
+      : _state = initialState,
+        _lastStartTag = lastStartTag;
+
+  List parse(String str) {
+    // Note: we need to pass bytes to the tokenizer if we want it to handle BOM.
+    var bytes = codepointsToUtf8(toCodepoints(str));
+    var tokenizer = new HtmlTokenizer(bytes, encoding: 'utf-8');
+    outputTokens = [];
+
+    // Note: we can't get a closure of the state method. However, we can
+    // create a new closure to invoke it via mirrors.
+    var mtok = reflect(tokenizer);
+    tokenizer.state = () => deprecatedFutureValue(
+        mtok.invokeAsync(new Symbol(_state), const [])).reflectee;
+
+    if (_lastStartTag != null) {
+      tokenizer.currentToken = new StartTagToken(_lastStartTag);
+    }
+
+    while (tokenizer.moveNext()) {
+      var token = tokenizer.current;
+      switch (token.kind) {
+        case TokenKind.characters:
+          processCharacters(token);
+          break;
+        case TokenKind.spaceCharacters:
+          processSpaceCharacters(token);
+          break;
+        case TokenKind.startTag:
+          processStartTag(token);
+          break;
+        case TokenKind.endTag:
+          processEndTag(token);
+          break;
+        case TokenKind.comment:
+          processComment(token);
+          break;
+        case TokenKind.doctype:
+          processDoctype(token);
+          break;
+        case TokenKind.parseError:
+          processParseError(token);
+          break;
+      }
+    }
+
+    return outputTokens;
+  }
+
+  void processDoctype(DoctypeToken token) {
+    outputTokens.add(["DOCTYPE", token.name, token.publicId,
+        token.systemId, token.correct]);
+  }
+
+  void processStartTag(StartTagToken token) {
+    outputTokens.add(["StartTag", token.name, token.data, token.selfClosing]);
+  }
+
+  void processEndTag(EndTagToken token) {
+    outputTokens.add(["EndTag", token.name, token.selfClosing]);
+  }
+
+  void processComment(StringToken token) {
+    outputTokens.add(["Comment", token.data]);
+  }
+
+  void processSpaceCharacters(StringToken token) {
+    processCharacters(token);
+  }
+
+  void processCharacters(StringToken token) {
+    outputTokens.add(["Character", token.data]);
+  }
+
+  void processEOF(token) {
+  }
+
+  void processParseError(StringToken token) {
+    // TODO(jmesserly): when debugging test failures it can be useful to add
+    // logging here like `print('ParseError $token');`. It would be nice to
+    // use the actual logging library.
+    outputTokens.add(["ParseError", token.data]);
+  }
+}
+
+List concatenateCharacterTokens(List tokens) {
+  var outputTokens = [];
+  for (var token in tokens) {
+    if (token.indexOf("ParseError") == -1 && token[0] == "Character") {
+      if (outputTokens.length > 0 &&
+          outputTokens.last.indexOf("ParseError") == -1 &&
+          outputTokens.last[0] == "Character") {
+
+        outputTokens.last[1] = '${outputTokens.last[1]}${token[1]}';
+      } else {
+        outputTokens.add(token);
+      }
+    } else {
+      outputTokens.add(token);
+    }
+  }
+  return outputTokens;
+}
+
+List normalizeTokens(List tokens) {
+  // TODO: convert tests to reflect arrays
+  for (int i = 0; i < tokens.length; i++) {
+    var token = tokens[i];
+    if (token[0] == 'ParseError') {
+      tokens[i] = token[0];
+    }
+  }
+  return tokens;
+}
+
+
+/**
+ * Test whether the test has passed or failed
+ *
+ * If the ignoreErrorOrder flag is set to true we don't test the relative
+ * positions of parse errors and non parse errors.
+ */
+void expectTokensMatch(List expectedTokens, List receivedTokens,
+    bool ignoreErrorOrder, [bool ignoreErrors = false, String message]) {
+
+  var checkSelfClosing = false;
+  for (var token in expectedTokens) {
+    if (token[0] == "StartTag" && token.length == 4
+        || token[0] == "EndTag" && token.length == 3) {
+      checkSelfClosing = true;
+      break;
+    }
+  }
+
+  if (!checkSelfClosing) {
+    for (var token in receivedTokens) {
+      if (token[0] == "StartTag" || token[0] == "EndTag") {
+        token.removeLast();
+      }
+    }
+  }
+
+  if (!ignoreErrorOrder && !ignoreErrors) {
+    expect(receivedTokens, equals(expectedTokens), reason: message);
+  } else {
+    // Sort the tokens into two groups; non-parse errors and parse errors
+    var expectedNonErrors = expectedTokens.where((t) => t != "ParseError");
+    var receivedNonErrors = receivedTokens.where((t) => t != "ParseError");
+
+    expect(receivedNonErrors, equals(expectedNonErrors), reason: message);
+    if (!ignoreErrors) {
+      var expectedParseErrors = expectedTokens.where((t) => t == "ParseError");
+      var receivedParseErrors = receivedTokens.where((t) => t == "ParseError");
+      expect(receivedParseErrors, equals(expectedParseErrors), reason: message);
+    }
+  }
+}
+
+void runTokenizerTest(Map testInfo) {
+  // XXX - move this out into the setup function
+  // concatenate all consecutive character tokens into a single token
+  if (testInfo.containsKey('doubleEscaped')) {
+    testInfo = unescape(testInfo);
+  }
+
+  var expected = concatenateCharacterTokens(testInfo['output']);
+  if (!testInfo.containsKey('lastStartTag')) {
+    testInfo['lastStartTag'] = null;
+  }
+  var parser = new TokenizerTestParser(testInfo['initialState'],
+      testInfo['lastStartTag']);
+  var tokens = parser.parse(testInfo['input']);
+  tokens = concatenateCharacterTokens(tokens);
+  var received = normalizeTokens(tokens);
+  var errorMsg = ["\n\nInitial state:",
+              testInfo['initialState'],
+              "\nInput:", testInfo['input'],
+              "\nExpected:", expected,
+              "\nreceived:", tokens].map((s) => '$s').join('\n');
+  var ignoreErrorOrder = testInfo['ignoreErrorOrder'];
+  if (ignoreErrorOrder == null) ignoreErrorOrder = false;
+
+  expectTokensMatch(expected, received, ignoreErrorOrder, true, errorMsg);
+}
+
+Map unescape(Map testInfo) {
+  // TODO(sigmundch,jmesserly): we currently use json.parse to unescape the
+  // unicode characters in the string, we should use a decoding that works with
+  // any control characters.
+  decode(inp) => inp == '\u0000' ? inp : json.parse('"$inp"');
+
+  testInfo["input"] = decode(testInfo["input"]);
+  for (var token in testInfo["output"]) {
+    if (token == "ParseError") {
+      continue;
+    } else {
+      token[1] = decode(token[1]);
+      if (token.length > 2) {
+        for (var pair in token[2]) {
+          var key = pair[0];
+          var value = pair[1];
+          token[2].remove(key);
+          token[2][decode(key)] = decode(value);
+        }
+      }
+    }
+  }
+  return testInfo;
+}
+
+
+String camelCase(String s) {
+  s = s.toLowerCase();
+  var result = new StringBuffer();
+  for (var match in new RegExp(r"\W+(\w)(\w+)").allMatches(s)) {
+    if (result.length == 0) result.write(s.substring(0, match.start));
+    result.write(match.group(1).toUpperCase());
+    result.write(match.group(2));
+  }
+  return result.toString();
+}
+
+void main() {
+  for (var path in getDataFiles('tokenizer')) {
+    if (!path.endsWith('.test')) continue;
+
+    var text = new File(path).readAsStringSync();
+    var tests = json.parse(text);
+    var testName = pathos.basenameWithoutExtension(path);
+    var testList = tests['tests'];
+    if (testList == null) continue;
+
+    group(testName, () {
+      for (int index = 0; index < testList.length; index++) {
+        final testInfo = testList[index];
+
+        testInfo.putIfAbsent("initialStates", () => ["Data state"]);
+        for (var initialState in testInfo["initialStates"]) {
+          test(testInfo["description"], () {
+            testInfo["initialState"] = camelCase(initialState);
+            runTokenizerTest(testInfo);
+          });
+        }
+      }
+    });
+  }
+}
diff --git a/pkg/unittest/lib/test_controller.js b/pkg/unittest/lib/test_controller.js
index 444e221..439b703 100644
--- a/pkg/unittest/lib/test_controller.js
+++ b/pkg/unittest/lib/test_controller.js
@@ -51,6 +51,8 @@
     driver.postMessage("STARTING", "*");
   }
 }
+// We call notifyStart here to notify the encapsulating browser.
+notifyStart();
 
 function notifyDone() {
   if (testRunner) testRunner.notifyDone();
@@ -158,8 +160,6 @@
 // dart2js will generate code to call this function instead of calling
 // Dart [main] directly. The argument is a closure that invokes main.
 function dartMainRunner(main) {
-  // We call notifyStart here to notify the encapsulating browser.
-  notifyStart();
   window.postMessage('dart-calling-main', '*');
   try {
     main();
diff --git a/pkg/watcher/lib/src/directory_watcher.dart b/pkg/watcher/lib/src/directory_watcher.dart
index c5dd9db..16a5cf1 100644
--- a/pkg/watcher/lib/src/directory_watcher.dart
+++ b/pkg/watcher/lib/src/directory_watcher.dart
@@ -11,6 +11,7 @@
 
 import 'async_queue.dart';
 import 'stat.dart';
+import 'utils.dart';
 import 'watch_event.dart';
 
 /// Watches the contents of a directory and emits [WatchEvent]s when something
@@ -118,19 +119,32 @@
     _filesToProcess.clear();
     _polledFiles.clear();
 
+    endListing() {
+      assert(_state != _WatchState.UNSUBSCRIBED);
+      _listSubscription = null;
+
+      // Null tells the queue consumer that we're done listing.
+      _filesToProcess.add(null);
+    }
+
     var stream = new Directory(directory).list(recursive: true);
     _listSubscription = stream.listen((entity) {
       assert(_state != _WatchState.UNSUBSCRIBED);
 
       if (entity is! File) return;
       _filesToProcess.add(entity.path);
-    }, onDone: () {
-      assert(_state != _WatchState.UNSUBSCRIBED);
-      _listSubscription = null;
+    }, onError: (error) {
+      if (!isDirectoryNotFoundException(error)) {
+        // It's some unknown error. Pipe it over to the event stream so the
+        // user can see it.
+        _events.addError(error);
+      }
 
-      // Null tells the queue consumer that we're done listing.
-      _filesToProcess.add(null);
-    });
+      // When an error occurs, we end the listing normally, which has the
+      // desired effect of marking all files that were in the directory as
+      // being removed.
+      endListing();
+    }, onDone: endListing, cancelOnError: true);
   }
 
   /// Processes [file] to determine if it has been modified since the last
diff --git a/pkg/watcher/lib/src/utils.dart b/pkg/watcher/lib/src/utils.dart
new file mode 100644
index 0000000..319835ec
--- /dev/null
+++ b/pkg/watcher/lib/src/utils.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library watcher.utils;
+
+import 'dart:io';
+
+/// Returns `true` if [error] is a [DirectoryException] for a missing directory.
+bool isDirectoryNotFoundException(error) {
+  if (error is! DirectoryException) return false;
+
+  // See dartbug.com/12461 and tests/standalone/io/directory_error_test.dart.
+  var notFoundCode = Platform.operatingSystem == "windows" ? 3 : 2;
+  return error.osError.errorCode == notFoundCode;
+}
diff --git a/pkg/watcher/test/directory_watcher_test.dart b/pkg/watcher/test/directory_watcher_test.dart
index 9070179..841dd08 100644
--- a/pkg/watcher/test/directory_watcher_test.dart
+++ b/pkg/watcher/test/directory_watcher_test.dart
@@ -86,4 +86,23 @@
     writeFile("a/b/c/d/file.txt");
     expectAddEvent("a/b/c/d/file.txt");
   });
+
+  test('watches a directory created after the watcher', () {
+    // Watch a subdirectory that doesn't exist yet.
+    createWatcher(dir: "a");
+
+    // This implicity creates it.
+    writeFile("a/b/c/d/file.txt");
+    expectAddEvent("a/b/c/d/file.txt");
+  });
+
+  test('when the watched directory is deleted, removes all files', () {
+    writeFile("dir/a.txt");
+    writeFile("dir/b.txt");
+
+    createWatcher(dir: "dir");
+
+    deleteDir("dir");
+    expectRemoveEvents(["dir/a.txt", "dir/b.txt"]);
+  });
 }
diff --git a/pkg/watcher/test/utils.dart b/pkg/watcher/test/utils.dart
index 65d4719..3bbe0e1 100644
--- a/pkg/watcher/test/utils.dart
+++ b/pkg/watcher/test/utils.dart
@@ -76,9 +76,17 @@
 /// Normally, this will pause the schedule until the watcher is done scanning
 /// and is polling for changes. If you pass `false` for [waitForReady], it will
 /// not schedule this delay.
-DirectoryWatcher createWatcher({bool waitForReady}) {
+///
+/// If [dir] is provided, watches a subdirectory in the sandbox with that name.
+DirectoryWatcher createWatcher({String dir, bool waitForReady}) {
+  if (dir == null) {
+    dir = _sandboxDir;
+  } else {
+    dir = p.join(_sandboxDir, dir);
+  }
+
   // Use a short delay to make the tests run quickly.
-  _watcher = new DirectoryWatcher(_sandboxDir,
+  _watcher = new DirectoryWatcher(dir,
       pollingDelay: new Duration(milliseconds: 100));
 
   // Wait until the scan is finished so that we don't miss changes to files
@@ -95,31 +103,48 @@
   return _watcher;
 }
 
-void expectEvent(ChangeType type, String path) {
-  // Immediately create the future. This ensures we don't register too late and
-  // drop the event before we receive it.
-  var future = _watcher.events.elementAt(_nextEvent++).then((event) {
-    expect(event, new _ChangeMatcher(type, path));
-  });
+/// Expects that the next set of events will all be changes of [type] on
+/// [paths].
+///
+/// Validates that events are delivered for all paths in [paths], but allows
+/// them in any order.
+void expectEvents(ChangeType type, Iterable<String> paths) {
+  var pathSet = paths
+      .map((path) => p.join(_sandboxDir, path))
+      .map(p.normalize)
+      .toSet();
 
-  // Make sure the schedule is watching it in case it fails.
-  currentSchedule.wrapFuture(future);
+  // Create an expectation for as many paths as we have.
+  var futures = [];
+
+  for (var i = 0; i < paths.length; i++) {
+    // Immediately create the futures. This ensures we don't register too
+    // late and drop the event before we receive it.
+    var future = _watcher.events.elementAt(_nextEvent++).then((event) {
+      expect(event.type, equals(type));
+      expect(pathSet, contains(event.path));
+
+      pathSet.remove(event.path);
+    });
+
+    // Make sure the schedule is watching it in case it fails.
+    currentSchedule.wrapFuture(future);
+
+    futures.add(future);
+  }
 
   // Schedule it so that later file modifications don't occur until after this
   // event is received.
-  schedule(() => future, "wait for $type event");
+  schedule(() => Future.wait(futures),
+      "wait for $type events on ${paths.join(', ')}");
 }
 
-void expectAddEvent(String path) {
-  expectEvent(ChangeType.ADD, p.join(_sandboxDir, path));
-}
+void expectAddEvent(String path) => expectEvents(ChangeType.ADD, [path]);
+void expectModifyEvent(String path) => expectEvents(ChangeType.MODIFY, [path]);
+void expectRemoveEvent(String path) => expectEvents(ChangeType.REMOVE, [path]);
 
-void expectModifyEvent(String path) {
-  expectEvent(ChangeType.MODIFY, p.join(_sandboxDir, path));
-}
-
-void expectRemoveEvent(String path) {
-  expectEvent(ChangeType.REMOVE, p.join(_sandboxDir, path));
+void expectRemoveEvents(Iterable<String> paths) {
+  expectEvents(ChangeType.REMOVE, paths);
 }
 
 /// Schedules writing a file in the sandbox at [path] with [contents].
@@ -175,6 +200,13 @@
   }, "rename file $from to $to");
 }
 
+/// Schedules deleting a directory in the sandbox at [path].
+void deleteDir(String path) {
+  schedule(() {
+    new Directory(p.join(_sandboxDir, path)).deleteSync(recursive: true);
+  }, "delete directory $path");
+}
+
 /// A [Matcher] for [WatchEvent]s.
 class _ChangeMatcher extends Matcher {
   /// The expected change.
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index f6e91c4..872a815 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -26,51 +26,54 @@
 namespace bin {
 
 static const int kBufferSize = 64 * 1024;
-static const int kStdioBufferSize = 16 * 1024;
+static const int kStdOverlappedBufferSize = 16 * 1024;
 
 static const int kInfinityTimeout = -1;
 static const int kTimeoutId = -1;
 static const int kShutdownId = -2;
 
-IOBuffer* IOBuffer::AllocateBuffer(int buffer_size, Operation operation) {
-  IOBuffer* buffer = new(buffer_size) IOBuffer(buffer_size, operation);
+OverlappedBuffer* OverlappedBuffer::AllocateBuffer(int buffer_size,
+                                                   Operation operation) {
+  OverlappedBuffer* buffer =
+      new(buffer_size) OverlappedBuffer(buffer_size, operation);
   return buffer;
 }
 
 
-IOBuffer* IOBuffer::AllocateAcceptBuffer(int buffer_size) {
-  IOBuffer* buffer = AllocateBuffer(buffer_size, kAccept);
+OverlappedBuffer* OverlappedBuffer::AllocateAcceptBuffer(int buffer_size) {
+  OverlappedBuffer* buffer = AllocateBuffer(buffer_size, kAccept);
   return buffer;
 }
 
 
-IOBuffer* IOBuffer::AllocateReadBuffer(int buffer_size) {
+OverlappedBuffer* OverlappedBuffer::AllocateReadBuffer(int buffer_size) {
   return AllocateBuffer(buffer_size, kRead);
 }
 
 
-IOBuffer* IOBuffer::AllocateWriteBuffer(int buffer_size) {
+OverlappedBuffer* OverlappedBuffer::AllocateWriteBuffer(int buffer_size) {
   return AllocateBuffer(buffer_size, kWrite);
 }
 
 
-IOBuffer* IOBuffer::AllocateDisconnectBuffer() {
+OverlappedBuffer* OverlappedBuffer::AllocateDisconnectBuffer() {
   return AllocateBuffer(0, kDisconnect);
 }
 
 
-void IOBuffer::DisposeBuffer(IOBuffer* buffer) {
+void OverlappedBuffer::DisposeBuffer(OverlappedBuffer* buffer) {
   delete buffer;
 }
 
 
-IOBuffer* IOBuffer::GetFromOverlapped(OVERLAPPED* overlapped) {
-  IOBuffer* buffer = CONTAINING_RECORD(overlapped, IOBuffer, overlapped_);
+OverlappedBuffer* OverlappedBuffer::GetFromOverlapped(OVERLAPPED* overlapped) {
+  OverlappedBuffer* buffer =
+      CONTAINING_RECORD(overlapped, OverlappedBuffer, overlapped_);
   return buffer;
 }
 
 
-int IOBuffer::Read(void* buffer, int num_bytes) {
+int OverlappedBuffer::Read(void* buffer, int num_bytes) {
   if (num_bytes > GetRemainingLength()) {
     num_bytes = GetRemainingLength();
   }
@@ -80,7 +83,7 @@
 }
 
 
-int IOBuffer::Write(const void* buffer, int num_bytes) {
+int OverlappedBuffer::Write(const void* buffer, int num_bytes) {
   ASSERT(num_bytes == buflen_);
   memcpy(GetBufferStart(), buffer, num_bytes);
   data_length_ = num_bytes;
@@ -88,7 +91,7 @@
 }
 
 
-int IOBuffer::GetRemainingLength() {
+int OverlappedBuffer::GetRemainingLength() {
   ASSERT(operation_ == kRead);
   return data_length_ - index_;
 }
@@ -183,7 +186,7 @@
 }
 
 
-void Handle::ReadComplete(IOBuffer* buffer) {
+void Handle::ReadComplete(OverlappedBuffer* buffer) {
   ScopedLock lock(this);
   // Currently only one outstanding read at the time.
   ASSERT(pending_read_ == buffer);
@@ -191,17 +194,17 @@
   if (!IsClosing() && !buffer->IsEmpty()) {
     data_ready_ = pending_read_;
   } else {
-    IOBuffer::DisposeBuffer(buffer);
+    OverlappedBuffer::DisposeBuffer(buffer);
   }
   pending_read_ = NULL;
 }
 
 
-void Handle::WriteComplete(IOBuffer* buffer) {
+void Handle::WriteComplete(OverlappedBuffer* buffer) {
   ScopedLock lock(this);
   // Currently only one outstanding write at the time.
   ASSERT(pending_write_ == buffer);
-  IOBuffer::DisposeBuffer(buffer);
+  OverlappedBuffer::DisposeBuffer(buffer);
   pending_write_ = NULL;
 }
 
@@ -215,11 +218,11 @@
 
 void Handle::ReadSyncCompleteAsync() {
   ASSERT(pending_read_ != NULL);
-  ASSERT(pending_read_->GetBufferSize() >= kStdioBufferSize);
+  ASSERT(pending_read_->GetBufferSize() >= kStdOverlappedBufferSize);
 
   DWORD buffer_size = pending_read_->GetBufferSize();
   if (GetFileType(handle_) == FILE_TYPE_CHAR) {
-    buffer_size = kStdioBufferSize;
+    buffer_size = kStdOverlappedBufferSize;
   }
   DWORD bytes_read = 0;
   BOOL ok = ReadFile(handle_,
@@ -248,7 +251,7 @@
   ScopedLock lock(this);
   ASSERT(type_ != kListenSocket);
   ASSERT(pending_read_ == NULL);
-  IOBuffer* buffer = IOBuffer::AllocateReadBuffer(kBufferSize);
+  OverlappedBuffer* buffer = OverlappedBuffer::AllocateReadBuffer(kBufferSize);
   if (SupportsOverlappedIO()) {
     ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
 
@@ -262,7 +265,7 @@
       pending_read_ = buffer;
       return true;
     }
-    IOBuffer::DisposeBuffer(buffer);
+    OverlappedBuffer::DisposeBuffer(buffer);
     HandleIssueError();
     return false;
   } else {
@@ -284,9 +287,9 @@
   ASSERT(type_ != kListenSocket);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_write_ != NULL);
-  ASSERT(pending_write_->operation() == IOBuffer::kWrite);
+  ASSERT(pending_write_->operation() == OverlappedBuffer::kWrite);
 
-  IOBuffer* buffer = pending_write_;
+  OverlappedBuffer* buffer = pending_write_;
   BOOL ok = WriteFile(handle_,
                       buffer->GetBufferStart(),
                       buffer->GetBufferSize(),
@@ -297,7 +300,7 @@
     pending_write_ = buffer;
     return true;
   }
-  IOBuffer::DisposeBuffer(buffer);
+  OverlappedBuffer::DisposeBuffer(buffer);
   HandleIssueError();
   return false;
 }
@@ -383,8 +386,8 @@
   static const int kAcceptExAddressAdditionalBytes = 16;
   static const int kAcceptExAddressStorageSize =
       sizeof(SOCKADDR_STORAGE) + kAcceptExAddressAdditionalBytes;
-  IOBuffer* buffer =
-      IOBuffer::AllocateAcceptBuffer(2 * kAcceptExAddressStorageSize);
+  OverlappedBuffer* buffer =
+      OverlappedBuffer::AllocateAcceptBuffer(2 * kAcceptExAddressStorageSize);
   DWORD received;
   BOOL ok;
   ok = AcceptEx_(socket(),
@@ -399,7 +402,7 @@
     if (WSAGetLastError() != WSA_IO_PENDING) {
       Log::PrintErr("AcceptEx failed: %d\n", WSAGetLastError());
       closesocket(buffer->client());
-      IOBuffer::DisposeBuffer(buffer);
+      OverlappedBuffer::DisposeBuffer(buffer);
       return false;
     }
   }
@@ -410,7 +413,8 @@
 }
 
 
-void ListenSocket::AcceptComplete(IOBuffer* buffer, HANDLE completion_port) {
+void ListenSocket::AcceptComplete(OverlappedBuffer* buffer,
+                                  HANDLE completion_port) {
   ScopedLock lock(this);
   if (!IsClosing()) {
     // Update the accepted socket to support the full range of API calls.
@@ -441,7 +445,7 @@
   }
 
   pending_accept_count_--;
-  IOBuffer::DisposeBuffer(buffer);
+  OverlappedBuffer::DisposeBuffer(buffer);
 }
 
 
@@ -508,7 +512,7 @@
   if (data_ready_ == NULL) return 0;
   num_bytes = data_ready_->Read(buffer, num_bytes);
   if (data_ready_->IsEmpty()) {
-    IOBuffer::DisposeBuffer(data_ready_);
+    OverlappedBuffer::DisposeBuffer(data_ready_);
     data_ready_ = NULL;
   }
   return num_bytes;
@@ -521,7 +525,7 @@
     if (pending_write_ != NULL) return 0;
     if (completion_port_ == INVALID_HANDLE_VALUE) return 0;
     if (num_bytes > kBufferSize) num_bytes = kBufferSize;
-    pending_write_ = IOBuffer::AllocateWriteBuffer(num_bytes);
+    pending_write_ = OverlappedBuffer::AllocateWriteBuffer(num_bytes);
     pending_write_->Write(buffer, num_bytes);
     if (!IssueWrite()) return -1;
     return num_bytes;
@@ -587,7 +591,7 @@
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_read_ == NULL);
 
-  IOBuffer* buffer = IOBuffer::AllocateReadBuffer(1024);
+  OverlappedBuffer* buffer = OverlappedBuffer::AllocateReadBuffer(1024);
 
   DWORD flags;
   flags = 0;
@@ -602,7 +606,7 @@
     pending_read_ = buffer;
     return true;
   }
-  IOBuffer::DisposeBuffer(buffer);
+  OverlappedBuffer::DisposeBuffer(buffer);
   pending_read_ = NULL;
   HandleIssueError();
   return false;
@@ -613,7 +617,7 @@
   ScopedLock lock(this);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_write_ != NULL);
-  ASSERT(pending_write_->operation() == IOBuffer::kWrite);
+  ASSERT(pending_write_->operation() == OverlappedBuffer::kWrite);
 
   int rc = WSASend(socket(),
                    pending_write_->GetWASBUF(),
@@ -625,7 +629,7 @@
   if (rc == NO_ERROR || WSAGetLastError() == WSA_IO_PENDING) {
     return true;
   }
-  IOBuffer::DisposeBuffer(pending_write_);
+  OverlappedBuffer::DisposeBuffer(pending_write_);
   pending_write_ = NULL;
   HandleIssueError();
   return false;
@@ -634,7 +638,7 @@
 
 void ClientSocket::IssueDisconnect() {
   Dart_Port p = port();
-  IOBuffer* buffer = IOBuffer::AllocateDisconnectBuffer();
+  OverlappedBuffer* buffer = OverlappedBuffer::AllocateDisconnectBuffer();
   BOOL ok = DisconnectEx_(
     socket(), buffer->GetCleanOverlapped(), TF_REUSE_SOCKET, 0);
   if (!ok && WSAGetLastError() != WSA_IO_PENDING) {
@@ -644,11 +648,11 @@
 }
 
 
-void ClientSocket::DisconnectComplete(IOBuffer* buffer) {
-  IOBuffer::DisposeBuffer(buffer);
+void ClientSocket::DisconnectComplete(OverlappedBuffer* buffer) {
+  OverlappedBuffer::DisposeBuffer(buffer);
   closesocket(socket());
   if (data_ready_ != NULL) {
-    IOBuffer::DisposeBuffer(data_ready_);
+    OverlappedBuffer::DisposeBuffer(data_ready_);
   }
   // When disconnect is complete get rid of the object.
   delete this;
@@ -776,7 +780,7 @@
 
 
 void EventHandlerImplementation::HandleAccept(ListenSocket* listen_socket,
-                                              IOBuffer* buffer) {
+                                              OverlappedBuffer* buffer) {
   listen_socket->AcceptComplete(buffer, completion_port_);
 
   if (!listen_socket->IsClosing()) {
@@ -810,7 +814,7 @@
 
 void EventHandlerImplementation::HandleRead(Handle* handle,
                                             int bytes,
-                                            IOBuffer* buffer) {
+                                            OverlappedBuffer* buffer) {
   buffer->set_data_length(bytes);
   handle->ReadComplete(buffer);
   if (bytes > 0) {
@@ -835,7 +839,7 @@
 
 void EventHandlerImplementation::HandleWrite(Handle* handle,
                                              int bytes,
-                                             IOBuffer* buffer) {
+                                             OverlappedBuffer* buffer) {
   handle->WriteComplete(buffer);
 
   if (bytes > 0) {
@@ -858,7 +862,7 @@
 void EventHandlerImplementation::HandleDisconnect(
     ClientSocket* client_socket,
     int bytes,
-    IOBuffer* buffer) {
+    OverlappedBuffer* buffer) {
   client_socket->DisconnectComplete(buffer);
 }
 
@@ -872,24 +876,24 @@
 void EventHandlerImplementation::HandleIOCompletion(DWORD bytes,
                                                     ULONG_PTR key,
                                                     OVERLAPPED* overlapped) {
-  IOBuffer* buffer = IOBuffer::GetFromOverlapped(overlapped);
+  OverlappedBuffer* buffer = OverlappedBuffer::GetFromOverlapped(overlapped);
   switch (buffer->operation()) {
-    case IOBuffer::kAccept: {
+    case OverlappedBuffer::kAccept: {
       ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(key);
       HandleAccept(listen_socket, buffer);
       break;
     }
-    case IOBuffer::kRead: {
+    case OverlappedBuffer::kRead: {
       Handle* handle = reinterpret_cast<Handle*>(key);
       HandleRead(handle, bytes, buffer);
       break;
     }
-    case IOBuffer::kWrite: {
+    case OverlappedBuffer::kWrite: {
       Handle* handle = reinterpret_cast<Handle*>(key);
       HandleWrite(handle, bytes, buffer);
       break;
     }
-    case IOBuffer::kDisconnect: {
+    case OverlappedBuffer::kDisconnect: {
       ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(key);
       HandleDisconnect(client_socket, bytes, buffer);
       break;
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 280175c..1c62200 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -34,21 +34,21 @@
 };
 
 
-// An IOBuffer encapsulates the OVERLAPPED structure and the
+// An OverlappedBuffer encapsulates the OVERLAPPED structure and the
 // associated data buffer. For accept it also contains the pre-created
 // socket for the client.
-class IOBuffer {
+class OverlappedBuffer {
  public:
   enum Operation { kAccept, kRead, kWrite, kDisconnect };
 
-  static IOBuffer* AllocateAcceptBuffer(int buffer_size);
-  static IOBuffer* AllocateReadBuffer(int buffer_size);
-  static IOBuffer* AllocateWriteBuffer(int buffer_size);
-  static IOBuffer* AllocateDisconnectBuffer();
-  static void DisposeBuffer(IOBuffer* buffer);
+  static OverlappedBuffer* AllocateAcceptBuffer(int buffer_size);
+  static OverlappedBuffer* AllocateReadBuffer(int buffer_size);
+  static OverlappedBuffer* AllocateWriteBuffer(int buffer_size);
+  static OverlappedBuffer* AllocateDisconnectBuffer();
+  static void DisposeBuffer(OverlappedBuffer* buffer);
 
   // Find the IO buffer from the OVERLAPPED address.
-  static IOBuffer* GetFromOverlapped(OVERLAPPED* overlapped);
+  static OverlappedBuffer* GetFromOverlapped(OVERLAPPED* overlapped);
 
   // Read data from a buffer which has been received. It will read up
   // to num_bytes bytes of data returning the actual number of bytes
@@ -88,7 +88,7 @@
   void set_data_length(int data_length) { data_length_ = data_length; }
 
  private:
-  IOBuffer(int buffer_size, Operation operation)
+  OverlappedBuffer(int buffer_size, Operation operation)
       : operation_(operation), buflen_(buffer_size) {
     memset(GetBufferStart(), 0, GetBufferSize());
     index_ = 0;
@@ -106,7 +106,8 @@
     free(buffer);
   }
 
-  static IOBuffer* AllocateBuffer(int buffer_size, Operation operation);
+  static OverlappedBuffer* AllocateBuffer(int buffer_size,
+                                          Operation operation);
 
   OVERLAPPED overlapped_;  // OVERLAPPED structure for overlapped IO.
   SOCKET client_;  // Used for AcceptEx client socket.
@@ -157,8 +158,8 @@
   virtual bool IssueWrite();
   bool HasPendingRead();
   bool HasPendingWrite();
-  void ReadComplete(IOBuffer* buffer);
-  void WriteComplete(IOBuffer* buffer);
+  void ReadComplete(OverlappedBuffer* buffer);
+  void WriteComplete(OverlappedBuffer* buffer);
 
   bool IsClosing() { return (flags_ & (1 << kClosing)) != 0; }
   bool IsClosedRead() { return (flags_ & (1 << kCloseRead)) != 0; }
@@ -230,9 +231,9 @@
   HANDLE completion_port_;
   EventHandlerImplementation* event_handler_;
 
-  IOBuffer* data_ready_;  // IO buffer for data ready to be read.
-  IOBuffer* pending_read_;  // IO buffer for pending read.
-  IOBuffer* pending_write_;  // IO buffer for pending write
+  OverlappedBuffer* data_ready_;  // Buffer for data ready to be read.
+  OverlappedBuffer* pending_read_;  // Buffer for pending read.
+  OverlappedBuffer* pending_write_;  // Buffer for pending write
 
   DWORD last_error_;
 
@@ -291,7 +292,7 @@
   // Internal interface used by the event handler.
   bool HasPendingAccept() { return pending_accept_count_ > 0; }
   bool IssueAccept();
-  void AcceptComplete(IOBuffer* buffer, HANDLE completion_port);
+  void AcceptComplete(OverlappedBuffer* buffer, HANDLE completion_port);
 
   virtual void EnsureInitialized(
     EventHandlerImplementation* event_handler);
@@ -342,7 +343,7 @@
   virtual bool IssueRead();
   virtual bool IssueWrite();
   void IssueDisconnect();
-  void DisconnectComplete(IOBuffer* buffer);
+  void DisconnectComplete(OverlappedBuffer* buffer);
 
   virtual void EnsureInitialized(
     EventHandlerImplementation* event_handler);
@@ -375,14 +376,14 @@
   int64_t GetTimeout();
   void HandleInterrupt(InterruptMessage* msg);
   void HandleTimeout();
-  void HandleAccept(ListenSocket* listen_socket, IOBuffer* buffer);
+  void HandleAccept(ListenSocket* listen_socket, OverlappedBuffer* buffer);
   void HandleClosed(Handle* handle);
   void HandleError(Handle* handle);
-  void HandleRead(Handle* handle, int bytes, IOBuffer* buffer);
-  void HandleWrite(Handle* handle, int bytes, IOBuffer* buffer);
+  void HandleRead(Handle* handle, int bytes, OverlappedBuffer* buffer);
+  void HandleWrite(Handle* handle, int bytes, OverlappedBuffer* buffer);
   void HandleDisconnect(ClientSocket* client_socket,
                         int bytes,
-                        IOBuffer* buffer);
+                        OverlappedBuffer* buffer);
   void HandleIOCompletion(DWORD bytes, ULONG_PTR key, OVERLAPPED* overlapped);
 
   HANDLE completion_port() { return completion_port_; }
diff --git a/runtime/bin/io_buffer.cc b/runtime/bin/io_buffer.cc
index dbc1047..ef08b4f 100644
--- a/runtime/bin/io_buffer.cc
+++ b/runtime/bin/io_buffer.cc
@@ -24,6 +24,7 @@
   return result;
 }
 
+
 uint8_t* IOBuffer::Allocate(intptr_t size) {
   return new uint8_t[size];
 }
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 30cfb06..a5c7170 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -37,6 +37,7 @@
   V(Platform_Environment, 0)                                                   \
   V(Platform_GetVersion, 0)                                                    \
   V(Process_Start, 10)                                                         \
+  V(Process_Wait, 5)                                                           \
   V(Process_Kill, 3)                                                           \
   V(Process_SetExitCode, 1)                                                    \
   V(Process_Exit, 1)                                                           \
@@ -50,8 +51,12 @@
   V(SecureSocket_RegisterBadCertificateCallback, 2)                            \
   V(SecureSocket_RegisterHandshakeCompleteCallback, 2)                         \
   V(SecureSocket_Renegotiate, 4)                                               \
-  V(SecureSocket_InitializeLibrary, 3)                                         \
+  V(SecureSocket_InitializeLibrary, 4)                                         \
   V(SecureSocket_AddCertificate, 2)                                            \
+  V(SecureSocket_ChangeTrust, 2)                                               \
+  V(SecureSocket_ImportCertificatesWithPrivateKeys, 2)                         \
+  V(SecureSocket_GetCertificate, 1)                                            \
+  V(SecureSocket_RemoveCertificate, 1)                                         \
   V(SecureSocket_NewServicePort, 0)                                            \
   V(SecureSocket_FilterPointer, 1)                                             \
   V(ServerSocket_CreateBindListen, 5)                                          \
diff --git a/runtime/bin/net/nss.gyp b/runtime/bin/net/nss.gyp
index e1c64e1..dbc685a 100644
--- a/runtime/bin/net/nss.gyp
+++ b/runtime/bin/net/nss.gyp
@@ -17,6 +17,7 @@
   'variables': {
     # Added by Dart.
     'nss_directory': '../../../third_party/nss',
+    'pkcs12_directory': '../../../third_party/nss_pkcs12',
     'conditions': [
       ['OS=="ios"', {
         'exclude_nss_root_certs%': 0,
@@ -1068,6 +1069,19 @@
         '<(nss_directory)/nss/lib/util/utilpars.h',
         '<(nss_directory)/nss/lib/util/utilparst.h',
         '<(nss_directory)/nss/lib/util/utilrename.h',
+        '<(pkcs12_directory)/p12creat.c',
+        '<(pkcs12_directory)/p12d.c',
+        '<(pkcs12_directory)/p12dec.c',
+        '<(pkcs12_directory)/p12e.c',
+        '<(pkcs12_directory)/p12.h',
+        '<(pkcs12_directory)/p12local.c',
+        '<(pkcs12_directory)/p12local.h',
+        '<(pkcs12_directory)/p12plcy.c',
+        '<(pkcs12_directory)/p12plcy.h',
+        '<(pkcs12_directory)/p12t.h',
+        '<(pkcs12_directory)/p12tmpl.c',
+        '<(pkcs12_directory)/pkcs12.h',
+        '<(pkcs12_directory)/pkcs12t.h',
       ],
       'sources!': [
         # mpi_arm.c is included by mpi_arm_mac.c.
@@ -1133,6 +1147,7 @@
         '<(nss_directory)/nss/lib/softoken',
         '<(nss_directory)/nss/lib/ssl',
         '<(nss_directory)/nss/lib/util',
+        '<(pkcs12_directory)',
       ],
       'direct_dependent_settings': {
         'defines': [
@@ -1159,6 +1174,7 @@
           '<(nss_directory)/nss/lib/smime',
           '<(nss_directory)/nss/lib/softoken',
           '<(nss_directory)/nss/lib/util',
+          '<(pkcs12_directory)',
         ],
       },
       'msvs_disabled_warnings': [4018, 4101, 4267, ],
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 21750f1..84cc360 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -74,7 +74,6 @@
     DartUtils::SetStringField(
         status_handle, "_errorMessage", "Path must be a builtin string");
     Dart_SetReturnValue(args, Dart_NewBoolean(false));
-    Dart_ExitScope();
     return;
   }
   const char* path = DartUtils::GetStringValue(path_handle);
@@ -87,7 +86,6 @@
                          &args_length);
   if (string_args == NULL) {
     Dart_SetReturnValue(args, Dart_NewBoolean(false));
-    Dart_ExitScope();
     return;
   }
   Dart_Handle working_directory_handle = Dart_GetNativeArgument(args, 3);
@@ -102,7 +100,6 @@
         status_handle, "_errorMessage",
         "WorkingDirectory must be a builtin string");
     Dart_SetReturnValue(args, Dart_NewBoolean(false));
-    Dart_ExitScope();
     return;
   }
   Dart_Handle environment = Dart_GetNativeArgument(args, 4);
@@ -117,7 +114,6 @@
     if (string_environment == NULL) {
       delete[] string_args;
       Dart_SetReturnValue(args, Dart_NewBoolean(false));
-      Dart_ExitScope();
       return;
     }
   }
@@ -159,6 +155,48 @@
 }
 
 
+void FUNCTION_NAME(Process_Wait)(Dart_NativeArguments args) {
+  Dart_Handle process =  Dart_GetNativeArgument(args, 0);
+  Dart_Handle stdin_handle =  Dart_GetNativeArgument(args, 1);
+  Dart_Handle stdout_handle =  Dart_GetNativeArgument(args, 2);
+  Dart_Handle stderr_handle =  Dart_GetNativeArgument(args, 3);
+  Dart_Handle exit_handle =  Dart_GetNativeArgument(args, 4);
+  intptr_t process_stdin;
+  intptr_t process_stdout;
+  intptr_t process_stderr;
+  intptr_t exit_event;
+  Socket::GetSocketIdNativeField(stdin_handle, &process_stdin);
+  Socket::GetSocketIdNativeField(stdout_handle, &process_stdout);
+  Socket::GetSocketIdNativeField(stderr_handle, &process_stderr);
+  Socket::GetSocketIdNativeField(exit_handle, &exit_event);
+  ProcessResult result;
+  intptr_t pid;
+  Process::GetProcessIdNativeField(process, &pid);
+  if (Process::Wait(pid,
+                    process_stdin,
+                    process_stdout,
+                    process_stderr,
+                    exit_event,
+                    &result)) {
+    Dart_Handle out = result.stdout_data();
+    if (Dart_IsError(out)) Dart_PropagateError(out);
+    Dart_Handle err = result.stderr_data();
+    if (Dart_IsError(err)) Dart_PropagateError(err);
+    Dart_Handle list = Dart_NewList(4);
+    Dart_ListSetAt(list, 0, Dart_NewInteger(pid));
+    Dart_ListSetAt(list, 1, Dart_NewInteger(result.exit_code()));
+    Dart_ListSetAt(list, 2, out);
+    Dart_ListSetAt(list, 3, err);
+    Dart_SetReturnValue(args, list);
+  } else {
+    Dart_Handle error = DartUtils::NewDartOSError();
+    Process::Kill(pid, 9);
+    if (Dart_IsError(error)) Dart_PropagateError(error);
+    Dart_ThrowException(error);
+  }
+}
+
+
 void FUNCTION_NAME(Process_Kill)(Dart_NativeArguments args) {
   Dart_Handle process = Dart_GetNativeArgument(args, 1);
   intptr_t pid = -1;
diff --git a/runtime/bin/process.h b/runtime/bin/process.h
index 8e82f39..02a9ecc 100644
--- a/runtime/bin/process.h
+++ b/runtime/bin/process.h
@@ -6,13 +6,41 @@
 #define BIN_PROCESS_H_
 
 #include "bin/builtin.h"
+#include "bin/io_buffer.h"
 #include "bin/thread.h"
 #include "platform/globals.h"
+#include "platform/utils.h"
 
 
 namespace dart {
 namespace bin {
 
+class ProcessResult {
+ public:
+  ProcessResult() : exit_code_(0) {}
+
+  void set_stdout_data(Dart_Handle stdout_data) {
+    stdout_data_ = stdout_data;
+  }
+  void set_stderr_data(Dart_Handle stderr_data) {
+    stderr_data_ = stderr_data;
+  }
+
+  void set_exit_code(intptr_t exit_code) { exit_code_ = exit_code; }
+
+  Dart_Handle stdout_data() { return stdout_data_; }
+  Dart_Handle stderr_data() { return stderr_data_; }
+  intptr_t exit_code() { return exit_code_; }
+
+ private:
+  Dart_Handle stdout_data_;
+  Dart_Handle stderr_data_;
+  intptr_t exit_code_;
+
+  DISALLOW_ALLOCATION();
+};
+
+
 class Process {
  public:
   // Start a new process providing access to stdin, stdout, stderr and
@@ -30,6 +58,13 @@
                    intptr_t* exit_handler,
                    char** os_error_message);
 
+  static bool Wait(intptr_t id,
+                   intptr_t in,
+                   intptr_t out,
+                   intptr_t err,
+                   intptr_t exit_handler,
+                   ProcessResult* result);
+
   // Kill a process with a given pid.
   static bool Kill(intptr_t id, int signal);
 
@@ -62,6 +97,108 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Process);
 };
 
+
+// Utility class for collecting the output when running a process
+// synchronously by using Process::Wait. This class is sub-classed in
+// the platform specific files to implement reading into the buffers
+// allocated.
+class BufferListBase {
+ protected:
+  static const intptr_t kBufferSize = 16 * 1024;
+
+  class BufferListNode {
+   public:
+    explicit BufferListNode(intptr_t size) {
+      data_ = new uint8_t[size];
+      if (data_ == NULL) FATAL("Allocation failed");
+      next_ = NULL;
+    }
+
+    ~BufferListNode() {
+      delete[] data_;
+    }
+
+    uint8_t* data_;
+    BufferListNode* next_;
+
+   private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BufferListNode);
+  };
+
+ public:
+  BufferListBase() : head_(NULL), tail_(NULL), data_size_(0), free_size_(0) {}
+  ~BufferListBase() {
+    ASSERT(head_ == NULL);
+    ASSERT(tail_ == NULL);
+  }
+
+  // Returns the collected data as a Uint8List. If an error occours an
+  // error handle is returned.
+  Dart_Handle GetData() {
+    uint8_t* buffer;
+    intptr_t buffer_position = 0;
+    Dart_Handle result = IOBuffer::Allocate(data_size_, &buffer);
+    if (Dart_IsError(result)) {
+      Free();
+      return result;
+    }
+    for (BufferListNode* current = head_;
+         current != NULL;
+         current = current->next_) {
+      intptr_t to_copy = dart::Utils::Minimum(data_size_, kBufferSize);
+      memmove(buffer + buffer_position, current->data_, to_copy);
+      buffer_position += to_copy;
+      data_size_ -= to_copy;
+    }
+    ASSERT(data_size_ == 0);
+    Free();
+    return result;
+  }
+
+ protected:
+  void Allocate() {
+    ASSERT(free_size_ == 0);
+    BufferListNode* node = new BufferListNode(kBufferSize);
+    if (head_ == NULL) {
+      head_ = node;
+      tail_ = node;
+    } else {
+      ASSERT(tail_->next_ == NULL);
+      tail_->next_ = node;
+      tail_ = node;
+    }
+    free_size_ = kBufferSize;
+  }
+
+  void Free() {
+    BufferListNode* current = head_;
+    while (current != NULL) {
+      BufferListNode* tmp = current;
+      current = current->next_;
+      delete tmp;
+    }
+    head_ = NULL;
+    tail_ = NULL;
+    data_size_ = 0;
+    free_size_ = 0;
+  }
+
+  // Returns the address of the first byte in the free space.
+  uint8_t* FreeSpaceAddress() {
+    return tail_->data_ + (kBufferSize - free_size_);
+  }
+
+  // Linked list for data collected.
+  BufferListNode* head_;
+  BufferListNode* tail_;
+
+  // Number of bytes of data collected in the linked list.
+  intptr_t data_size_;
+
+  // Number of free bytes in the last node in the list.
+  intptr_t free_size_;
+};
+
 }  // namespace bin
 }  // namespace dart
 
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index 6102e70..5e7e838 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -21,6 +21,7 @@
 #include "bin/log.h"
 #include "bin/thread.h"
 
+
 extern char **environ;
 
 
@@ -568,6 +569,123 @@
 }
 
 
+class BufferList: public BufferListBase {
+ public:
+  bool Read(int fd, intptr_t available) {
+    // Read all available bytes.
+    while (available > 0) {
+      if (free_size_ == 0) Allocate();
+      ASSERT(free_size_ > 0);
+      ASSERT(free_size_ <= kBufferSize);
+      intptr_t block_size = dart::Utils::Minimum(free_size_, available);
+      intptr_t bytes = TEMP_FAILURE_RETRY(read(
+          fd,
+          reinterpret_cast<void*>(FreeSpaceAddress()),
+          block_size));
+      if (bytes < 0) return false;
+      data_size_ += bytes;
+      free_size_ -= bytes;
+      available -= bytes;
+    }
+    return true;
+  }
+};
+
+
+static bool CloseProcessBuffers(struct pollfd fds[3]) {
+  int e = errno;
+  VOID_TEMP_FAILURE_RETRY(close(fds[0].fd));
+  VOID_TEMP_FAILURE_RETRY(close(fds[1].fd));
+  VOID_TEMP_FAILURE_RETRY(close(fds[2].fd));
+  errno = e;
+  return false;
+}
+
+
+bool Process::Wait(intptr_t pid,
+                   intptr_t in,
+                   intptr_t out,
+                   intptr_t err,
+                   intptr_t exit_event,
+                   ProcessResult* result) {
+  // Close input to the process right away.
+  VOID_TEMP_FAILURE_RETRY(close(in));
+
+  // There is no return from this function using Dart_PropagateError
+  // as memory used by the buffer lists is freed through their
+  // destructors.
+  BufferList out_data;
+  BufferList err_data;
+  union {
+    uint8_t bytes[8];
+    int32_t ints[2];
+  } exit_code_data;
+
+  struct pollfd fds[3];
+  fds[0].fd = out;
+  fds[1].fd = err;
+  fds[2].fd = exit_event;
+
+  for (int i = 0; i < 3; i++) {
+    fds[i].events = POLLIN;
+  }
+
+  int alive = 3;
+  while (alive > 0) {
+    // Blocking call waiting for events from the child process.
+    if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) {
+      return CloseProcessBuffers(fds);
+    }
+
+    // Process incoming data.
+    int current_alive = alive;
+    for (int i = 0; i < current_alive; i++) {
+      if (fds[i].revents & POLLIN) {
+        intptr_t avail = FDUtils::AvailableBytes(fds[i].fd);
+        if (fds[i].fd == out) {
+          if (!out_data.Read(out, avail)) {
+            return CloseProcessBuffers(fds);
+          }
+        } else if (fds[i].fd == err) {
+          if (!err_data.Read(err, avail)) {
+            return CloseProcessBuffers(fds);
+          }
+        } else if (fds[i].fd == exit_event) {
+          if (avail == 8) {
+            intptr_t b = TEMP_FAILURE_RETRY(read(exit_event,
+                                                 exit_code_data.bytes, 8));
+            if (b != 8) {
+              return CloseProcessBuffers(fds);
+            }
+          }
+        } else {
+          UNREACHABLE();
+        }
+      }
+      if (fds[i].revents & POLLHUP) {
+        VOID_TEMP_FAILURE_RETRY(close(fds[i].fd));
+        alive--;
+        if (i < alive) {
+          fds[i] = fds[alive];
+        }
+      }
+    }
+  }
+
+  // All handles closed and all data read.
+  result->set_stdout_data(out_data.GetData());
+  result->set_stderr_data(err_data.GetData());
+
+  // Calculate the exit code.
+  intptr_t exit_code = exit_code_data.ints[0];
+  intptr_t negative = exit_code_data.ints[1];
+  if (negative) exit_code = -exit_code;
+  result->set_exit_code(exit_code);
+
+  return true;
+}
+
+
 bool Process::Kill(intptr_t id, int signal) {
   return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1);
 }
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index c87523c..78d3cdb 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -567,6 +567,129 @@
 }
 
 
+class BufferList: public BufferListBase {
+ public:
+  bool Read(int fd, intptr_t available) {
+    // Read all available bytes.
+    while (available > 0) {
+      if (free_size_ == 0) Allocate();
+      ASSERT(free_size_ > 0);
+      ASSERT(free_size_ <= kBufferSize);
+      size_t block_size = dart::Utils::Minimum(free_size_, available);
+      ssize_t bytes = TEMP_FAILURE_RETRY(read(
+          fd,
+          reinterpret_cast<void*>(FreeSpaceAddress()),
+          block_size));
+      if (bytes < 0) return false;
+      data_size_ += bytes;
+      free_size_ -= bytes;
+      available -= bytes;
+    }
+    return true;
+  }
+};
+
+
+static bool CloseProcessBuffers(struct pollfd fds[3]) {
+  int e = errno;
+  VOID_TEMP_FAILURE_RETRY(close(fds[0].fd));
+  VOID_TEMP_FAILURE_RETRY(close(fds[1].fd));
+  VOID_TEMP_FAILURE_RETRY(close(fds[2].fd));
+  errno = e;
+  return false;
+}
+
+
+bool Process::Wait(intptr_t pid,
+                   intptr_t in,
+                   intptr_t out,
+                   intptr_t err,
+                   intptr_t exit_event,
+                   ProcessResult* result) {
+  // Close input to the process right away.
+  VOID_TEMP_FAILURE_RETRY(close(in));
+
+  // There is no return from this function using Dart_PropagateError
+  // as memory used by the buffer lists is freed through their
+  // destructors.
+  BufferList out_data;
+  BufferList err_data;
+  union {
+    uint8_t bytes[8];
+    int32_t ints[2];
+  } exit_code_data;
+
+  struct pollfd fds[3];
+  fds[0].fd = out;
+  fds[1].fd = err;
+  fds[2].fd = exit_event;
+
+  for (int i = 0; i < 3; i++) {
+    fds[i].events = POLLIN;
+  }
+
+  int alive = 3;
+  while (alive > 0) {
+    // Blocking call waiting for events from the child process.
+    if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) {
+      return CloseProcessBuffers(fds);
+    }
+
+    // Process incoming data.
+    int current_alive = alive;
+    for (int i = 0; i < current_alive; i++) {
+      intptr_t avail;
+      if (fds[i].revents & POLLIN) {
+        avail = FDUtils::AvailableBytes(fds[i].fd);
+        // On Mac OS POLLIN can be set with zero available
+        // bytes. POLLHUP is most likely also set in this case.
+        if (avail > 0) {
+          if (fds[i].fd == out) {
+            if (!out_data.Read(out, avail)) {
+              return CloseProcessBuffers(fds);
+            }
+          } else if (fds[i].fd == err) {
+            if (!err_data.Read(err, avail)) {
+              return CloseProcessBuffers(fds);
+            }
+          } else if (fds[i].fd == exit_event) {
+            if (avail == 8) {
+              intptr_t b = TEMP_FAILURE_RETRY(read(fds[i].fd,
+                                                   exit_code_data.bytes, 8));
+              if (b != 8) {
+                return CloseProcessBuffers(fds);
+              }
+            }
+          } else {
+            UNREACHABLE();
+          }
+        }
+      }
+      if (fds[i].revents & POLLHUP ||
+          ((fds[i].revents & POLLIN) && avail == 0)) {
+        VOID_TEMP_FAILURE_RETRY(close(fds[i].fd));
+        alive--;
+        if (i < alive) {
+          fds[i] = fds[alive];
+        }
+      }
+    }
+  }
+
+  // All handles closed and all data read.
+  result->set_stdout_data(out_data.GetData());
+  result->set_stderr_data(err_data.GetData());
+
+  // Calculate the exit code.
+  intptr_t exit_code = exit_code_data.ints[0];
+  intptr_t negative = exit_code_data.ints[1];
+  if (negative) exit_code = -exit_code;
+  result->set_exit_code(exit_code);
+
+  return true;
+}
+
+
 bool Process::Kill(intptr_t id, int signal) {
   return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1);
 }
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index 6d69139..62489ca 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -49,6 +49,25 @@
                                      stdoutEncoding,
                                      stderrEncoding);
   }
+
+  /* patch */ static ProcessResult runSync(
+      String executable,
+      List<String> arguments,
+      {String workingDirectory,
+       Map<String, String> environment,
+       bool includeParentEnvironment: true,
+       bool runInShell: false,
+       Encoding stdoutEncoding: Encoding.SYSTEM,
+       Encoding stderrEncoding: Encoding.SYSTEM}) {
+    return _runNonInteractiveProcessSync(executable,
+                                         arguments,
+                                         workingDirectory,
+                                         environment,
+                                         includeParentEnvironment,
+                                         runInShell,
+                                         stdoutEncoding,
+                                         stderrEncoding);
+  }
 }
 
 
@@ -278,6 +297,43 @@
     return completer.future;
   }
 
+  ProcessResult _runAndWait(Encoding stdoutEncoding,
+                            Encoding stderrEncoding) {
+    var status = new _ProcessStartStatus();
+    bool success = _startNative(_path,
+                                _arguments,
+                                _workingDirectory,
+                                _environment,
+                                _stdin._sink._nativeSocket,
+                                _stdout._stream._nativeSocket,
+                                _stderr._stream._nativeSocket,
+                                _exitHandler._nativeSocket,
+                                status);
+    if (!success) {
+      throw new ProcessException(_path,
+                                 _arguments,
+                                 status._errorMessage,
+                                 status._errorCode);
+    }
+
+    var result = _wait(
+        _stdin._sink._nativeSocket,
+        _stdout._stream._nativeSocket,
+        _stderr._stream._nativeSocket,
+        _exitHandler._nativeSocket);
+
+    getOutput(output, encoding) {
+      if (stderrEncoding == null) return output;
+      return _decodeString(output, encoding);
+    }
+
+    return new _ProcessResult(
+        result[0],
+        result[1],
+        getOutput(result[2], stdoutEncoding),
+        getOutput(result[3], stderrEncoding));
+  }
+
   bool _startNative(String path,
                     List<String> arguments,
                     String workingDirectory,
@@ -288,6 +344,11 @@
                     _NativeSocket exitHandler,
                     _ProcessStartStatus status) native "Process_Start";
 
+  _wait(_NativeSocket stdin,
+        _NativeSocket stdout,
+        _NativeSocket stderr,
+        _NativeSocket exitHandler) native "Process_Wait";
+
   Stream<List<int>> get stdout {
     return _stdout;
   }
@@ -383,6 +444,24 @@
   });
 }
 
+ProcessResult _runNonInteractiveProcessSync(
+      String executable,
+      List<String> arguments,
+      String workingDirectory,
+      Map<String, String> environment,
+      bool includeParentEnvironment,
+      bool runInShell,
+      Encoding stdoutEncoding,
+      Encoding stderrEncoding) {
+  var process = new _ProcessImpl(executable,
+                                 arguments,
+                                 workingDirectory,
+                                 environment,
+                                 includeParentEnvironment,
+                                 runInShell);
+  return process._runAndWait(stdoutEncoding, stderrEncoding);
+}
+
 
 class _ProcessResult implements ProcessResult {
   const _ProcessResult(int this.pid,
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index f6c809a..d3efd4c 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -642,6 +642,201 @@
 }
 
 
+class BufferList: public BufferListBase {
+ public:
+  BufferList() : read_pending_(true) { }
+
+  // Indicate that data has been read into the buffer provided to
+  // overlapped read.
+  void DataIsRead(intptr_t size) {
+    ASSERT(read_pending_ == true);
+    data_size_ += size;
+    free_size_ -= size;
+    ASSERT(free_size_ >= 0);
+    read_pending_ = false;
+  }
+
+  // The access to the read buffer for overlapped read.
+  void GetReadBuffer(uint8_t** buffer, intptr_t* size) {
+    ASSERT(!read_pending_);
+    if (free_size_ == 0) Allocate();
+    ASSERT(free_size_ > 0);
+    ASSERT(free_size_ <= kBufferSize);
+    *buffer = FreeSpaceAddress();
+    *size = free_size_;
+    read_pending_ = true;
+  }
+
+  intptr_t GetDataSize() {
+    return data_size_;
+  }
+
+  uint8_t* GetFirstDataBuffer() {
+    ASSERT(head_ != NULL);
+    ASSERT(head_ == tail_);
+    ASSERT(data_size_ <= kBufferSize);
+    return head_->data_;
+  }
+
+  void FreeDataBuffer() {
+    Free();
+  }
+
+ private:
+  bool read_pending_;
+};
+
+
+class OverlappedHandle {
+ public:
+  void Init(HANDLE handle, HANDLE event) {
+    handle_ = handle;
+    event_ = event;
+    ClearOverlapped();
+  }
+
+  bool HasEvent(HANDLE event) {
+    return event_ == event;
+  }
+
+  bool Read() {
+    // Get the data read as a result of a completed overlapped operation.
+    if (overlapped_.InternalHigh > 0) {
+      buffer_.DataIsRead(overlapped_.InternalHigh);
+    } else {
+      buffer_.DataIsRead(0);
+    }
+
+    // Keep reading until error or pending operation.
+    while (true) {
+      ClearOverlapped();
+      uint8_t* buffer;
+      intptr_t buffer_size;
+      buffer_.GetReadBuffer(&buffer, &buffer_size);
+      BOOL ok = ReadFile(handle_, buffer, buffer_size, NULL, &overlapped_);
+      if (!ok) return GetLastError() == ERROR_IO_PENDING;
+      buffer_.DataIsRead(overlapped_.InternalHigh);
+    }
+  }
+
+  Dart_Handle GetData() {
+    return buffer_.GetData();
+  }
+
+  intptr_t GetDataSize() {
+    return buffer_.GetDataSize();
+  }
+
+  uint8_t* GetFirstDataBuffer() {
+    return buffer_.GetFirstDataBuffer();
+  }
+
+  void FreeDataBuffer() {
+    return buffer_.FreeDataBuffer();
+  }
+
+  void Close() {
+    CloseHandle(handle_);
+    CloseHandle(event_);
+    handle_ = INVALID_HANDLE_VALUE;
+    overlapped_.hEvent = INVALID_HANDLE_VALUE;
+  }
+
+ private:
+  void ClearOverlapped() {
+    memset(&overlapped_, 0, sizeof(overlapped_));
+    overlapped_.hEvent = event_;
+  }
+
+  OVERLAPPED overlapped_;
+  HANDLE handle_;
+  HANDLE event_;
+  BufferList buffer_;
+
+  DISALLOW_ALLOCATION();
+};
+
+
+bool Process::Wait(intptr_t pid,
+                   intptr_t in,
+                   intptr_t out,
+                   intptr_t err,
+                   intptr_t exit_event,
+                   ProcessResult* result) {
+  // Close input to the process right away.
+  reinterpret_cast<FileHandle*>(in)->Close();
+
+  // All pipes created to the sub-process support overlapped IO.
+  FileHandle* stdout_handle = reinterpret_cast<FileHandle*>(out);
+  ASSERT(stdout_handle->SupportsOverlappedIO());
+  FileHandle* stderr_handle = reinterpret_cast<FileHandle*>(err);
+  ASSERT(stderr_handle->SupportsOverlappedIO());
+  FileHandle* exit_handle = reinterpret_cast<FileHandle*>(exit_event);
+  ASSERT(exit_handle->SupportsOverlappedIO());
+
+  // Create three events for overlapped IO. These are created as already
+  // signalled to ensure they have read called at least once.
+  static const int kHandles = 3;
+  HANDLE events[kHandles];
+  for (int i = 0; i < kHandles; i++) {
+    events[i] = CreateEvent(NULL, FALSE, TRUE, NULL);
+  }
+
+  // Setup the structure for handling overlapped IO.
+  OverlappedHandle oh[kHandles];
+  oh[0].Init(stdout_handle->handle(), events[0]);
+  oh[1].Init(stderr_handle->handle(), events[1]);
+  oh[2].Init(exit_handle->handle(), events[2]);
+
+  // Continue until all handles are closed.
+  int alive = kHandles;
+  while (alive > 0) {
+    // Blocking call waiting for events from the child process.
+    DWORD wait_result = WaitForMultipleObjects(alive, events, FALSE, INFINITE);
+
+    // Find the handle signalled.
+    int index = wait_result - WAIT_OBJECT_0;
+    for (int i = 0; i < kHandles; i++) {
+      if (oh[i].HasEvent(events[index])) {
+        bool ok = oh[i].Read();
+        if (!ok) {
+          if (GetLastError() == ERROR_BROKEN_PIPE) {
+            oh[i].Close();
+            alive--;
+            if (index < alive) {
+              events[index] = events[alive];
+            }
+          } else if (err != ERROR_IO_PENDING) {
+            DWORD e = GetLastError();
+            oh[0].Close();
+            oh[1].Close();
+            oh[2].Close();
+            SetLastError(e);
+            return false;
+          }
+        }
+        break;
+      }
+    }
+  }
+
+  // All handles closed and all data read.
+  result->set_stdout_data(oh[0].GetData());
+  result->set_stderr_data(oh[1].GetData());
+
+  // Calculate the exit code.
+  ASSERT(oh[2].GetDataSize() == 8);
+  uint32_t exit[2];
+  memcpy(&exit, oh[2].GetFirstDataBuffer(), sizeof(exit));
+  oh[2].FreeDataBuffer();
+  intptr_t exit_code = exit[0];
+  intptr_t negative = exit[1];
+  if (negative) exit_code = -exit_code;
+  result->set_exit_code(exit_code);
+  return true;
+}
+
+
 bool Process::Kill(intptr_t id, int signal) {
   USE(signal);  // signal is not used on windows.
   HANDLE process_handle;
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 8a45101..2bfa94f 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -10,9 +10,12 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <certdb.h>
 #include <key.h>
 #include <keyt.h>
 #include <nss.h>
+#include <p12.h>
+#include <p12plcy.h>
 #include <pk11pub.h>
 #include <prerror.h>
 #include <prinit.h>
@@ -37,10 +40,10 @@
 
 bool SSLFilter::library_initialized_ = false;
 // To protect library initialization.
-dart::Mutex* SSLFilter::mutex_ = new dart::Mutex();
+dart::Mutex* SSLFilter::mutex = new dart::Mutex();
 // The password is needed when creating secure server sockets.  It can
 // be null if only secure client sockets are used.
-const char* SSLFilter::password_ = NULL;
+char* SSLFilter::password_ = NULL;
 
 // Forward declaration.
 static void ProcessFilter(Dart_Port dest_port_id,
@@ -229,7 +232,7 @@
                                       &certificate_database));
   } else if (!Dart_IsNull(certificate_database_object)) {
     Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "Non-String certificate directory argument to SetCertificateDatabase"));
+        "SecureSocket.initialize: database argument is not a String or null"));
   }
   // Leave certificate_database as NULL if no value was provided.
 
@@ -244,7 +247,7 @@
     password = "";
   } else {
     Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "Password argument to SetCertificateDatabase is not a String or null"));
+        "SecureSocket.initialize: password argument is not a String or null"));
   }
 
   Dart_Handle builtin_roots_object =
@@ -255,10 +258,22 @@
     ThrowIfError(Dart_BooleanValue(builtin_roots_object, &builtin_roots));
   } else {
     Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "UseBuiltinRoots argument to SetCertificateDatabase is not a bool"));
+        "SecureSocket.initialize: useBuiltinRoots argument is not a bool"));
   }
 
-  SSLFilter::InitializeLibrary(certificate_database, password, builtin_roots);
+  Dart_Handle read_only_object =
+      ThrowIfError(Dart_GetNativeArgument(args, 3));
+  // Check that the type is boolean, and get the boolean value from it.
+  bool read_only = true;
+  if (Dart_IsBoolean(read_only_object)) {
+    ThrowIfError(Dart_BooleanValue(read_only_object, &read_only));
+  } else {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecureSocket.initialize: readOnly argument is not a bool"));
+  }
+
+  SSLFilter::InitializeLibrary(
+      certificate_database, password, builtin_roots, read_only);
 }
 
 
@@ -300,6 +315,14 @@
 }
 
 
+char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
+  if (!retry) {
+    return PL_strdup(static_cast<char*>(arg));  // Freed by NSS internals.
+  }
+  return NULL;
+}
+
+
 void FUNCTION_NAME(SecureSocket_AddCertificate)
     (Dart_NativeArguments args) {
   Dart_Handle certificate_object =
@@ -324,18 +347,28 @@
   ThrowIfError(Dart_StringToCString(trust_object,
                                     &trust_string));
 
+  PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+  SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword());
+  PK11_FreeSlot(slot);
+  if (status == SECFailure) {
+    ThrowPRException("CertificateException",
+                     "Could not authenticate to certificate database");
+  }
+
   CERTCertificate* cert = CERT_DecodeCertFromPackage(
       reinterpret_cast<char*>(certificate), length);
   if (cert == NULL) {
     ThrowPRException("CertificateException", "Certificate cannot be decoded");
   }
   CERTCertTrust trust;
-  SECStatus status = CERT_DecodeTrustString(&trust, trust_string);
+  status = CERT_DecodeTrustString(&trust, trust_string);
   if (status != SECSuccess) {
     ThrowPRException("CertificateException", "Trust string cannot be decoded");
   }
-
-  status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
+  {
+    MutexLocker locker(SSLFilter::mutex);
+    status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
+  }
   if (status != SECSuccess) {
     ThrowPRException("CertificateException", "Cannot set trust attributes");
   }
@@ -345,6 +378,204 @@
 }
 
 
+/*
+ * Called by the PKCS#12 decoder if a certificate's nickname collides with
+ * the nickname of a different existing certificate in the database.
+ */
+SECItem* nickname_callback(SECItem *old_nickname,
+                           PRBool *cancel,
+                           void *arg) {
+  *cancel = PR_TRUE;
+  return NULL;
+}
+
+
+void FUNCTION_NAME(SecureSocket_ImportCertificatesWithPrivateKeys)
+    (Dart_NativeArguments args) {
+  Dart_Handle pk12_object = ThrowIfError(Dart_GetNativeArgument(args, 0));
+  if (!Dart_IsList(pk12_object)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecureSocket.importPrivateCertificates: certificates is not a List"));
+  }
+
+  Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+  if (!Dart_IsString(password_object)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecureSocket.importPrivateCertificates: password is not a String"));
+  }
+
+  intptr_t length;
+  ThrowIfError(Dart_ListLength(pk12_object, &length));
+  uint8_t* pk12 = Dart_ScopeAllocate(length);
+  if (pk12 == NULL) {
+    FATAL("Out of memory in SecureSocket.importPrivateCertificates");
+  }
+  ThrowIfError(Dart_ListGetAsBytes(pk12_object, 0, pk12, length));
+
+  // A big-endian Unicode (UTF16) password.
+  intptr_t password_length;
+  ThrowIfError(Dart_StringLength(password_object, &password_length));
+  password_length++;
+  uint16_t* password = reinterpret_cast<uint16_t*>(
+      Dart_ScopeAllocate(sizeof(uint16_t) * password_length));
+  if (password == NULL) {
+    FATAL("Out of memory in SecureSocket.importPrivateCertificates");
+  }
+  intptr_t returned_length = password_length;
+  ThrowIfError(Dart_StringToUTF16(password_object, password, &returned_length));
+  ASSERT(password_length == returned_length + 1);
+  password[password_length - 1] = 0;
+  for (int i = 0; i < password_length; ++i) {
+    password[i] = Utils::HostToBigEndian16(password[i]);
+  }
+  SECItem p12_password;
+  p12_password.type = siBuffer;
+  p12_password.data = reinterpret_cast<unsigned char*>(password);
+  p12_password.len = sizeof(uint16_t) * password_length;
+
+  Dart_SetReturnValue(args, Dart_Null());
+  // Set the password callback for the certificate database we are importing to.
+  // The password for a slot is gotten from a callback, and it is freed by the
+  // caller of the callback.  The argument to the callback comes from the wincx
+  // argument to a PK11 function.
+  PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+  SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword());
+  if (status == SECFailure) {
+    PK11_FreeSlot(slot);
+    ThrowPRException("CertificateException",
+                     "Could not authenticate to certificate database");
+  }
+
+  SEC_PKCS12DecoderContext* context = SEC_PKCS12DecoderStart(
+      &p12_password,
+      slot,
+      SSLFilter::GetPassword(),
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL);
+  PK11_FreeSlot(slot);
+  if (!context) {
+    FATAL("Unexpected error: SecureSocket.addPrivateCertificates DecoderStart");
+  }
+  bool success;
+  {
+    MutexLocker locker(SSLFilter::mutex);
+    success =
+        SECSuccess == SEC_PKCS12DecoderUpdate(context, pk12, length) &&
+        SECSuccess == SEC_PKCS12DecoderVerify(context) &&
+        SECSuccess == SEC_PKCS12DecoderValidateBags(context,
+                                                    nickname_callback) &&
+        SECSuccess == SEC_PKCS12DecoderImportBags(context);
+  }
+  SEC_PKCS12DecoderFinish(context);
+  if (!success) {
+    ThrowPRException("CertificateException", "Could not import PKCS#12 file");
+  }
+}
+
+
+void FUNCTION_NAME(SecureSocket_ChangeTrust)(Dart_NativeArguments args) {
+  Dart_Handle nickname_object = ThrowIfError(Dart_GetNativeArgument(args, 0));
+  if (!Dart_IsString(nickname_object)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecureSocket.changeTrust: nickname argument is not a String"));
+  }
+  const char* nickname;
+  ThrowIfError(Dart_StringToCString(nickname_object, &nickname));
+
+  Dart_Handle trust_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+  if (!Dart_IsString(trust_object)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecureSocket.changeTrust: trust argument is not a String"));
+  }
+  const char* trust_string;
+  ThrowIfError(Dart_StringToCString(trust_object, &trust_string));
+
+  PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+  SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword());
+  if (status == SECFailure) {
+    ThrowPRException("CertificateException",
+                     "Could not authenticate to certificate database");
+  }
+  PK11_FreeSlot(slot);
+
+  CERTCertificate* certificate =
+      PK11_FindCertFromNickname(nickname, SSLFilter::GetPassword());
+  if (certificate == NULL) {
+    ThrowCertificateException("Cannot find certificate with nickname %s",
+                              nickname);
+  }
+  CERTCertTrust trust;
+  if (SECSuccess != CERT_DecodeTrustString(&trust, trust_string)) {
+    CERT_DestroyCertificate(certificate);
+    ThrowPRException("CertificateException", "Trust string cannot be decoded");
+  }
+  {
+    MutexLocker locker(SSLFilter::mutex);
+    status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), certificate, &trust);
+  }
+  if (status != SECSuccess) {
+    CERT_DestroyCertificate(certificate);
+    ThrowCertificateException("Cannot set trust on certificate %s", nickname);
+  }
+  Dart_SetReturnValue(args, X509FromCertificate(certificate));
+  CERT_DestroyCertificate(certificate);
+}
+
+
+void FUNCTION_NAME(SecureSocket_GetCertificate)(Dart_NativeArguments args) {
+  Dart_Handle nickname_object = ThrowIfError(Dart_GetNativeArgument(args, 0));
+  if (!Dart_IsString(nickname_object)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecureSocket.getCertificate: nickname argument is not a String"));
+  }
+  const char* nickname;
+  ThrowIfError(Dart_StringToCString(nickname_object, &nickname));
+
+  CERTCertificate* certificate = PK11_FindCertFromNickname(
+                                     nickname, SSLFilter::GetPassword());
+  if (certificate != NULL) {
+    Dart_SetReturnValue(args, X509FromCertificate(certificate));
+    CERT_DestroyCertificate(certificate);
+  }
+}
+
+
+void FUNCTION_NAME(SecureSocket_RemoveCertificate)(Dart_NativeArguments args) {
+  Dart_Handle nickname_object =
+      ThrowIfError(Dart_GetNativeArgument(args, 0));
+  if (!Dart_IsString(nickname_object)) {
+    Dart_ThrowException(DartUtils::NewDartArgumentError(
+        "SecureSocket.removeCertificate: nickname is not a String"));
+  }
+  const char* nickname;
+  ThrowIfError(Dart_StringToCString(nickname_object, &nickname));
+
+  CERTCertificate* certificate =
+      PK11_FindCertFromNickname(nickname, SSLFilter::GetPassword());
+  if (certificate == NULL) {
+    ThrowCertificateException("Cannot find certificate with nickname %s",
+                              nickname);
+  }
+  SECKEYPrivateKey* key =
+      PK11_FindKeyByAnyCert(certificate, SSLFilter::GetPassword());
+  // Free the copy returned from FindKeyByAnyCert.
+  SECKEY_DestroyPrivateKey(key);
+  SECStatus status;
+  {
+    MutexLocker locker(SSLFilter::mutex);
+    status = (key == NULL) ?
+        SEC_DeletePermCertificate(certificate) :
+        PK11_DeleteTokenCertAndKey(certificate, SSLFilter::GetPassword());
+  }
+  CERT_DestroyCertificate(certificate);
+  if (status != SECSuccess) {
+    ThrowCertificateException("Cannot remove certificate %s", nickname);
+  }
+}
+
 
 void FUNCTION_NAME(SecureSocket_PeerCertificate)
     (Dart_NativeArguments args) {
@@ -494,7 +725,7 @@
 
 void SSLFilter::Init(Dart_Handle dart_this) {
   if (!library_initialized_) {
-    InitializeLibrary(NULL, "", true, false);
+    InitializeLibrary(NULL, "", true, true, false);
   }
   ASSERT(string_start_ == NULL);
   string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
@@ -567,14 +798,6 @@
 }
 
 
-char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
-  if (!retry) {
-    return PL_strdup(static_cast<char*>(arg));  // Freed by NSS internals.
-  }
-  return NULL;
-}
-
-
 static const char* builtin_roots_module =
 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
     "name=\"Root Certs\" library=\"libnssckbi.so\"";
@@ -591,8 +814,9 @@
 void SSLFilter::InitializeLibrary(const char* certificate_database,
                                   const char* password,
                                   bool use_builtin_root_certificates,
+                                  bool read_only,
                                   bool report_duplicate_initialization) {
-  MutexLocker locker(mutex_);
+  MutexLocker locker(mutex);
   SECStatus status;
   if (!library_initialized_) {
     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
@@ -600,7 +824,7 @@
     if (certificate_database == NULL || certificate_database[0] == '\0') {
       status = NSS_NoDB_Init(NULL);
       if (status != SECSuccess) {
-        mutex_->Unlock();  // MutexLocker destructor not called when throwing.
+        mutex->Unlock();  // MutexLocker destructor not called when throwing.
         ThrowPRException("TlsException",
                          "Failed NSS_NoDB_Init call.");
       }
@@ -608,13 +832,13 @@
         SECMODModule* module = SECMOD_LoadUserModule(
             const_cast<char*>(builtin_roots_module), NULL, PR_FALSE);
         if (!module) {
-          mutex_->Unlock();  // MutexLocker destructor not called when throwing.
+          mutex->Unlock();  // MutexLocker destructor not called when throwing.
           ThrowPRException("TlsException",
                            "Failed to load builtin root certificates.");
         }
       }
     } else {
-      PRUint32 init_flags = NSS_INIT_READONLY;
+      PRUint32 init_flags = read_only ? NSS_INIT_READONLY : 0;
       if (!use_builtin_root_certificates) {
         init_flags |= NSS_INIT_NOMODDB;
       }
@@ -624,7 +848,7 @@
                               SECMOD_DB,
                               init_flags);
       if (status != SECSuccess) {
-        mutex_->Unlock();  // MutexLocker destructor not called when throwing.
+        mutex->Unlock();  // MutexLocker destructor not called when throwing.
         ThrowPRException("TlsException",
                          "Failed NSS_Init call.");
       }
@@ -633,28 +857,34 @@
     }
     library_initialized_ = true;
 
+    // Allow encoding and decoding of private keys in PKCS#12 files.
+    SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
+    SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
+    SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
+
     status = NSS_SetDomesticPolicy();
     if (status != SECSuccess) {
-      mutex_->Unlock();  // MutexLocker destructor not called when throwing.
+      mutex->Unlock();  // MutexLocker destructor not called when throwing.
       ThrowPRException("TlsException",
                        "Failed NSS_SetDomesticPolicy call.");
     }
+
     // Enable TLS, as well as SSL3 and SSL2.
     status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
     if (status != SECSuccess) {
-      mutex_->Unlock();  // MutexLocker destructor not called when throwing.
+      mutex->Unlock();  // MutexLocker destructor not called when throwing.
       ThrowPRException("TlsException",
                        "Failed SSL_OptionSetDefault enable TLS call.");
     }
     status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
     if (status != SECSuccess) {
-      mutex_->Unlock();  // MutexLocker destructor not called when throwing.
+      mutex->Unlock();  // MutexLocker destructor not called when throwing.
       ThrowPRException("TlsException",
                        "Failed SSL_ConfigServerSessionIDCache call.");
     }
 
   } else if (report_duplicate_initialization) {
-    mutex_->Unlock();  // MutexLocker destructor not called when throwing.
+    mutex->Unlock();  // MutexLocker destructor not called when throwing.
     // Like ThrowPRException, without adding an OSError.
     Dart_ThrowException(DartUtils::NewDartIOException("TlsException",
         "Called SecureSocket.initialize more than once",
@@ -729,23 +959,20 @@
           const_cast<char*>(certificate_name));
       if (certificate == NULL) {
         ThrowCertificateException(
-            "Cannot find server certificate by distinguished name: %s",
+            "Cannot find server certificate with distinguished name %s",
             certificate_name);
       }
     } else {
       // Look up certificate using the nickname certificate_name.
       certificate = PK11_FindCertFromNickname(
-          const_cast<char*>(certificate_name),
-          static_cast<void*>(const_cast<char*>(password_)));
+          const_cast<char*>(certificate_name), GetPassword());
       if (certificate == NULL) {
         ThrowCertificateException(
-            "Cannot find server certificate by nickname: %s",
+            "Cannot find server certificate with nickname %s",
             certificate_name);
       }
     }
-    SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(
-        certificate,
-        static_cast<void*>(const_cast<char*>(password_)));
+    SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(certificate, GetPassword());
     if (key == NULL) {
       CERT_DestroyCertificate(certificate);
       if (PR_GetError() == -8177) {
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index 304ccd5..cdb4f65 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -46,6 +46,8 @@
     kFirstEncrypted = kReadEncrypted
   };
 
+  static dart::Mutex* mutex;  // To protect library initialization.
+
   SSLFilter()
       : callback_error(NULL),
         string_start_(NULL),
@@ -87,15 +89,17 @@
   static void InitializeLibrary(const char* certificate_database,
                                 const char* password,
                                 bool use_builtin_root_certificates,
+                                bool read_only,
                                 bool report_duplicate_initialization = true);
   static Dart_Port GetServicePort();
   Dart_Handle callback_error;
 
+  static char* GetPassword() { return password_; }
+
  private:
   static const int kMemioBufferSize = 20 * KB;
   static bool library_initialized_;
-  static const char* password_;
-  static dart::Mutex* mutex_;  // To protect library initialization.
+  static char* password_;
   static NativeService filter_service_;
 
   uint8_t* buffers_[kNumBuffers];
@@ -115,7 +119,6 @@
     return static_cast<BufferIndex>(i) >= kFirstEncrypted;
   }
   void InitializeBuffers(Dart_Handle dart_this);
-  void InitializePlatformData();
 
   DISALLOW_COPY_AND_ASSIGN(SSLFilter);
 };
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index 96d6565a..13640b2 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -8,12 +8,27 @@
 
   /* patch */ static void initialize({String database,
                                       String password,
-                                      bool useBuiltinRoots: true})
+                                      bool useBuiltinRoots: true,
+                                      bool readOnly: true})
       native "SecureSocket_InitializeLibrary";
 
   /* patch */ static X509Certificate addCertificate(List<int> certificate,
                                                     String trust)
       native "SecureSocket_AddCertificate";
+
+  /* patch */ static importCertificatesWithPrivateKeys(List<int> certificates,
+                                                       String password)
+      native "SecureSocket_ImportCertificatesWithPrivateKeys";
+
+  /* patch */ static X509Certificate changeTrust(String nickname,
+                                                 String trust)
+      native "SecureSocket_ChangeTrust";
+
+  /* patch */ static X509Certificate getCertificate(String nickname)
+      native "SecureSocket_GetCertificate";
+
+  /* patch */ static removeCertificate(String nickname)
+      native "SecureSocket_RemoveCertificate";
 }
 
 
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 255c704..aa3963a 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1523,7 +1523,6 @@
  */
 DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, intptr_t* size);
 
-
 /**
  * Converts a String into an ExternalString.
  * The original object is morphed into an external string object.
@@ -1554,6 +1553,23 @@
                                                 void* peer,
                                                 Dart_PeerFinalizer cback);
 
+/**
+ * Retrieves some properties associated with a String.
+ * Properties retrieved are:
+ * - character size of the string (one or two byte)
+ * - length of the string
+ * - peer pointer of string if it is an external string.
+ * \param str A String.
+ * \param char_size Returns the character size of the String.
+ * \param str_len Returns the length of the String.
+ * \param peer Returns the peer pointer if the String is an external String.
+ * \return Success if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle str,
+                                                 intptr_t* char_size,
+                                                 intptr_t* str_len,
+                                                 void** peer);
 
 /*
  * =====
@@ -1982,11 +1998,26 @@
                                                intptr_t* value);
 
 /**
+ * Gets a string native argument at some index.
+ * \param args Native arguments structure.
+ * \param arg_index Index of the desired argument in the structure above.
+ * \param peer Returns the peer pointer if the String is an external String.
+ * \return the String object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args,
+                                                     int arg_index,
+                                                     void** peer);
+
+/**
  * Sets the return value for a native function.
  */
 DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
                                      Dart_Handle retval);
 
+DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args,
+                                               Dart_WeakPersistentHandle rval);
+
 DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
                                             bool retval);
 
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 66efd3a..e1cc262 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -155,7 +155,7 @@
     return offset >= 0;
   }
 
-  /* patch */ void removeAll(Iterable objectsToRemove) {
+  /* patch */ void removeAll(Iterable<Object> objectsToRemove) {
     for (Object object in objectsToRemove) {
       _table._remove(object);
       _table._checkCapacity();
diff --git a/runtime/lib/corelib_sources.gypi b/runtime/lib/corelib_sources.gypi
index ec3c6c1..14a53b2 100644
--- a/runtime/lib/corelib_sources.gypi
+++ b/runtime/lib/corelib_sources.gypi
@@ -21,6 +21,7 @@
     'errors_patch.dart',
     'expando_patch.dart',
     'function.cc',
+    'function.dart',
     'function_patch.dart',
     'growable_array.cc',
     'growable_array.dart',
diff --git a/runtime/lib/date_patch.dart b/runtime/lib/date_patch.dart
index f959723..b1f1e83 100644
--- a/runtime/lib/date_patch.dart
+++ b/runtime/lib/date_patch.dart
@@ -190,7 +190,7 @@
         ((y.remainder(100) != 0) || (y.remainder(400) == 0));
   }
 
-  static _brokenDownDateToMillisecondsSinceEpoch(
+  /* patch */ static int _brokenDownDateToMillisecondsSinceEpoch(
       int year, int month, int day,
       int hour, int minute, int second, int millisecond,
       bool isUtc) {
@@ -249,7 +249,7 @@
    * Leap seconds are ignored.
    * Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9.
    */
-  static _equivalentYear(int year) {
+  static int _equivalentYear(int year) {
     // Returns the week day (in range 0 - 6).
     // 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year.
     // 1/1/1967 was a Sunday (i.e. weekday 0).
diff --git a/runtime/lib/expando_patch.dart b/runtime/lib/expando_patch.dart
index 07ed0b7..7608861 100644
--- a/runtime/lib/expando_patch.dart
+++ b/runtime/lib/expando_patch.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 patch class Expando<T> {
-  /* patch */ Expando([this.name])
+  /* patch */ Expando([String this.name])
       : _data = new List(_minSize),
         _used = 0;
 
diff --git a/runtime/lib/function.cc b/runtime/lib/function.cc
index 6f3fb4a..8c41892 100644
--- a/runtime/lib/function.cc
+++ b/runtime/lib/function.cc
@@ -27,4 +27,50 @@
   return result.raw();
 }
 
+
+DEFINE_NATIVE_ENTRY(FunctionImpl_equals, 2) {
+  const Instance& receiver = Instance::CheckedHandle(
+      isolate, arguments->NativeArgAt(0));
+  ASSERT(receiver.IsClosure());
+  GET_NATIVE_ARGUMENT(Instance, other, arguments->NativeArgAt(1));
+  if (receiver.raw() == other.raw()) return Bool::True().raw();
+  if (other.IsClosure()) {
+    const Function& func_a = Function::Handle(Closure::function(receiver));
+    const Function& func_b = Function::Handle(Closure::function(other));
+    if (func_a.raw() == func_b.raw()) {
+      ASSERT(!func_a.IsImplicitStaticClosureFunction());
+      if (func_a.IsImplicitInstanceClosureFunction()) {
+        const Context& context_a = Context::Handle(Closure::context(receiver));
+        const Context& context_b = Context::Handle(Closure::context(other));
+        const Instance& receiver_a = Instance::Handle(context_a.At(0));
+        const Instance& receiver_b = Instance::Handle(context_b.At(0));
+        if (receiver_a.raw() == receiver_b.raw()) return Bool::True().raw();
+      }
+    }
+  }
+  return Bool::False().raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(FunctionImpl_hashCode, 1) {
+  const Instance& receiver = Instance::CheckedHandle(
+      isolate, arguments->NativeArgAt(0));
+  if (receiver.IsClosure()) {
+    const Function& func = Function::Handle(Closure::function(receiver));
+    // Hash together name, class name and signature.
+    const Class& cls = Class::Handle(func.Owner());
+    intptr_t result = String::Handle(func.name()).Hash();
+    result += String::Handle(func.Signature()).Hash();
+    result += String::Handle(cls.Name()).Hash();
+    // Finalize hash value like for strings so that it fits into a smi.
+    result += result << 3;
+    result ^= result >> 11;
+    result += result << 15;
+    result &= ((static_cast<intptr_t>(1) << String::kHashBits) - 1);
+    return Smi::New(result);
+  }
+  UNREACHABLE();
+  return Object::null();
+}
+
 }  // namespace dart
diff --git a/runtime/lib/function.dart b/runtime/lib/function.dart
new file mode 100644
index 0000000..a75b564
--- /dev/null
+++ b/runtime/lib/function.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class _FunctionImpl implements Function {
+
+  bool operator ==(other) native "FunctionImpl_equals";
+
+  int get hashCode native "FunctionImpl_hashCode";
+}
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index dc29527..fa87faf 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -223,9 +223,11 @@
 }
 
 
+// Passing true for 'silent' prevents throwing JavascriptIntegerOverflow.
 static RawInteger* ShiftOperationHelper(Token::Kind kind,
                                         const Integer& value,
-                                        const Smi& amount) {
+                                        const Smi& amount,
+                                        const bool silent = false) {
   if (amount.Value() < 0) {
     const Array& args = Array::Handle(Array::New(1));
     args.SetAt(0, amount);
@@ -233,7 +235,7 @@
   }
   if (value.IsSmi()) {
     const Smi& smi_value = Smi::Cast(value);
-    return smi_value.ShiftOp(kind, amount);
+    return smi_value.ShiftOp(kind, amount, silent);
   }
   Bigint& big_value = Bigint::Handle();
   if (value.IsMint()) {
@@ -242,9 +244,9 @@
     if ((count + amount.Value()) < Mint::kBits) {
       switch (kind) {
         case Token::kSHL:
-          return Integer::New(mint_value << amount.Value());
+          return Integer::New(mint_value << amount.Value(), Heap::kNew, silent);
         case Token::kSHR:
-          return Integer::New(mint_value >> amount.Value());
+          return Integer::New(mint_value >> amount.Value(), Heap::kNew, silent);
         default:
           UNIMPLEMENTED();
       }
@@ -268,6 +270,28 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Integer_leftShiftWithMask32, 3) {
+  const Integer& value = Integer::CheckedHandle(arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, shift_count, arguments->NativeArgAt(1));
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, mask, arguments->NativeArgAt(2));
+  ASSERT(CheckInteger(value));
+  ASSERT(CheckInteger(shift_count));
+  ASSERT(CheckInteger(mask));
+  if (!shift_count.IsSmi()) {
+    // Shift count is too large..
+    const Instance& exception =
+        Instance::Handle(isolate->object_store()->out_of_memory());
+    Exceptions::Throw(exception);
+  }
+  const Smi& smi_shift_count = Smi::Cast(shift_count);
+  const Integer& shift_result = Integer::Handle(
+      ShiftOperationHelper(Token::kSHL, value, smi_shift_count, true));
+  const Integer& result =
+      Integer::Handle(shift_result.BitOp(Token::kBIT_AND, mask));
+  return result.AsValidInteger();
+}
+
+
 DEFINE_NATIVE_ENTRY(Smi_shrFromInt, 2) {
   const Smi& amount = Smi::CheckedHandle(arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index c687e09..aaf5712 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -172,7 +172,10 @@
         result *= base;
       }
       exponent >>= 1;
-      base *= base;
+      // Skip unnecessary operation (can overflow to Mint or Bigint).
+      if (exponent != 0) {
+        base *= base;
+      }
     }
     return result;
   }
@@ -213,6 +216,8 @@
     }
     return buffer.toString();
   }
+
+  _leftShiftWithMask32(count, mask)  native "Integer_leftShiftWithMask32";
 }
 
 class _Smi extends _IntegerImplementation implements int {
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 2280aa9..a2713d1 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -187,9 +187,9 @@
     return _portInternal;
   }
 
-  /* patch */ static spawnFunction(void topLevelFunction(),
+  /* patch */ static SendPort spawnFunction(void topLevelFunction(),
       [bool unhandledExceptionCallback(IsolateUnhandledException e)])
       native "isolate_spawnFunction";
 
-  /* patch */ static spawnUri(String uri) native "isolate_spawnUri";
+  /* patch */ static SendPort spawnUri(String uri) native "isolate_spawnUri";
 }
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index d0e4524..7ab68b6 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -45,20 +45,31 @@
 }
 
 
-static RawInstance* CreateParameterMirrorList(const Function& func) {
+static RawInstance* CreateParameterMirrorList(const Function& func,
+                                              const Instance& owner_mirror) {
   HANDLESCOPE(Isolate::Current());
-  const intptr_t param_cnt = func.num_fixed_parameters() -
-                             func.NumImplicitParameters() +
-                             func.NumOptionalParameters();
-  const Array& results = Array::Handle(Array::New(param_cnt));
-  const Array& args = Array::Handle(Array::New(3));
+  const intptr_t implicit_param_count = func.NumImplicitParameters();
+  const intptr_t non_implicit_param_count = func.NumParameters() -
+                                            implicit_param_count;
+  const intptr_t index_of_first_optional_param =
+      non_implicit_param_count - func.NumOptionalParameters();
+  const intptr_t index_of_first_named_param =
+      non_implicit_param_count - func.NumOptionalNamedParameters();
+  const Array& results = Array::Handle(Array::New(non_implicit_param_count));
+  const Array& args = Array::Handle(Array::New(6));
   args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
+  args.SetAt(2, owner_mirror);
   Smi& pos = Smi::Handle();
+  String& name = String::Handle();
   Instance& param = Instance::Handle();
-  for (intptr_t i = 0; i < param_cnt; i++) {
+  for (intptr_t i = 0; i < non_implicit_param_count; i++) {
     pos ^= Smi::New(i);
-    args.SetAt(1, pos);
-    args.SetAt(2, (i >= func.num_fixed_parameters()) ?
+    name ^= func.ParameterNameAt(implicit_param_count + i);
+    args.SetAt(1, name);
+    args.SetAt(3, pos);
+    args.SetAt(4, (i >= index_of_first_optional_param) ?
+        Bool::True() : Bool::False());
+    args.SetAt(5, (i >= index_of_first_named_param) ?
         Bool::True() : Bool::False());
     param ^= CreateMirror(Symbols::_LocalParameterMirrorImpl(), args);
     results.SetAt(i, param);
@@ -378,12 +389,12 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(FunctionTypeMirror_parameters, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+DEFINE_NATIVE_ENTRY(FunctionTypeMirror_parameters, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
   const Class& cls = Class::Handle(ref.GetClassReferent());
-  const Function& func = Function::Handle(CallMethod(cls));
-  ASSERT(!func.IsNull());
-  return CreateParameterMirrorList(func);
+  const Function& func = Function::Handle(cls.signature_function());
+  return CreateParameterMirrorList(func, owner);
 }
 
 
@@ -461,15 +472,9 @@
   }
 
   const Array& fields = Array::Handle(klass.fields());
-  // Some special types like 'dynamic' have a null fields list, but they should
-  // not wind up as the reflectees of ClassMirrors.
-  ASSERT(!fields.IsNull());
   const intptr_t num_fields = fields.Length();
 
   const Array& functions = Array::Handle(klass.functions());
-  // Some special types like 'dynamic' have a null functions list, but they
-  // should not wind up as the reflectees of ClassMirrors.
-  ASSERT(!functions.IsNull());
   const intptr_t num_functions = functions.Length();
 
   Instance& member_mirror = Instance::Handle();
@@ -486,9 +491,10 @@
   Function& func = Function::Handle();
   for (intptr_t i = 0; i < num_functions; i++) {
     func ^= functions.At(i);
-    if (func.kind() == RawFunction::kRegularFunction ||
+    if (func.is_visible() &&
+        (func.kind() == RawFunction::kRegularFunction ||
         func.kind() == RawFunction::kGetterFunction ||
-        func.kind() == RawFunction::kSetterFunction) {
+        func.kind() == RawFunction::kSetterFunction)) {
       member_mirror = CreateMethodMirror(func, owner_mirror);
       member_mirrors.Add(member_mirror);
     }
@@ -511,9 +517,6 @@
   }
 
   const Array& functions = Array::Handle(klass.functions());
-  // Some special types like 'dynamic' have a null functions list, but they
-  // should not wind up as the reflectees of ClassMirrors.
-  ASSERT(!functions.IsNull());
   const intptr_t num_functions = functions.Length();
 
   Instance& constructor_mirror = Instance::Handle();
@@ -590,19 +593,33 @@
 DEFINE_NATIVE_ENTRY(ClassMirror_type_arguments, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
 
-  const AbstractTypeArguments& args =
-      AbstractTypeArguments::Handle(type.arguments());
-  if (args.IsNull()) {
-    return Object::empty_array().raw();
-  }
-
   const Class& cls = Class::Handle(type.type_class());
   const intptr_t num_params = cls.NumTypeParameters();
-  const intptr_t num_inherited_args = args.Length() - num_params;
+
+  if (num_params == 0) {
+    return Object::empty_array().raw();
+  }
 
   const Array& result = Array::Handle(Array::New(num_params));
   AbstractType& arg_type = AbstractType::Handle();
   Instance& type_mirror = Instance::Handle();
+  const AbstractTypeArguments& args =
+      AbstractTypeArguments::Handle(type.arguments());
+
+  // Handle argument lists that have been optimized away, because either no
+  // arguments have been provided, or all arguments are dynamic. Return a list
+  // of typemirrors on dynamic in this case.
+  if (args.IsNull()) {
+    arg_type ^= Object::dynamic_type();
+    type_mirror ^= CreateTypeMirror(arg_type);
+    for (intptr_t i = 0; i < num_params; i++) {
+      result.SetAt(i, type_mirror);
+    }
+    return result.raw();
+  }
+
+  ASSERT(args.Length() >= num_params);
+  const intptr_t num_inherited_args = args.Length() - num_params;
   for (intptr_t i = 0; i < num_params; i++) {
     arg_type ^= args.TypeAt(i + num_inherited_args);
     type_mirror = CreateTypeMirror(arg_type);
@@ -635,7 +652,7 @@
   // Note "arguments" is already the internal arguments with the receiver as
   // the first element.
   Object& result = Object::Handle();
-  if (function.IsNull()) {
+  if (function.IsNull() || !function.is_visible()) {
     const Array& arguments_descriptor =
         Array::Handle(ArgumentsDescriptor::New(arguments.Length()));
     result = DartEntry::InvokeNoSuchMethod(receiver,
@@ -894,7 +911,8 @@
   if (function.IsNull() ||
       !function.AreValidArgumentCounts(number_of_arguments,
                                        /* named_args */ 0,
-                                       NULL)) {
+                                       NULL) ||
+      !function.is_visible()) {
     ThrowNoSuchMethod(klass,
                       function_name,
                       function,
@@ -929,7 +947,7 @@
     const Function& getter = Function::Handle(
         klass.LookupStaticFunctionAllowPrivate(internal_getter_name));
 
-    if (getter.IsNull()) {
+    if (getter.IsNull() || !getter.is_visible()) {
       ThrowNoSuchMethod(klass,
                         getter_name,
                         getter,
@@ -968,7 +986,7 @@
     const Function& setter = Function::Handle(
       klass.LookupStaticFunctionAllowPrivate(internal_setter_name));
 
-    if (setter.IsNull()) {
+    if (setter.IsNull() || !setter.is_visible()) {
       ThrowNoSuchMethod(klass,
                         setter_name,
                         setter,
@@ -1035,7 +1053,8 @@
      !constructor.AreValidArgumentCounts(number_of_arguments +
                                          constructor.NumImplicitParameters(),
                                          /* named args */ 0,
-                                         NULL)) {
+                                         NULL) ||
+     !constructor.is_visible()) {
     // Pretend we didn't find the constructor at all when the arity is wrong
     // so as to produce the same NoSuchMethodError as the non-reflective case.
     constructor = Function::null();
@@ -1086,7 +1105,8 @@
   if (function.IsNull() ||
      !function.AreValidArgumentCounts(number_of_arguments,
                                       0,
-                                      NULL) ) {
+                                      NULL) ||
+     !function.is_visible()) {
     ThrowNoSuchMethod(library,
                       function_name,
                       function,
@@ -1134,7 +1154,7 @@
     getter = klass.LookupStaticFunctionAllowPrivate(internal_getter_name);
   }
 
-  if (!getter.IsNull()) {
+  if (!getter.IsNull() && getter.is_visible()) {
     // Invoke the getter and return the result.
     const Object& result = Object::Handle(
         DartEntry::InvokeFunction(getter, Object::empty_array()));
@@ -1183,7 +1203,7 @@
     const Function& setter = Function::Handle(
         library.LookupFunctionAllowPrivate(internal_setter_name,
                                            &ambiguity_error_msg));
-    if (setter.IsNull()) {
+    if (setter.IsNull() || !setter.is_visible()) {
       if (ambiguity_error_msg.IsNull()) {
         ThrowNoSuchMethod(library,
                           setter_name,
@@ -1240,10 +1260,11 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(MethodMirror_parameters, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+DEFINE_NATIVE_ENTRY(MethodMirror_parameters, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
   const Function& func = Function::Handle(ref.GetFunctionReferent());
-  return CreateParameterMirrorList(func);
+  return CreateParameterMirrorList(func, owner);
 }
 
 
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 7c7331f..88a89cc 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -669,7 +669,7 @@
   static Type _FunctionTypeMirror_return_type(reflectee)
       native "FunctionTypeMirror_return_type";
 
-  static List<ParameterMirror> _FunctionTypeMirror_parameters(reflectee)
+  List<ParameterMirror> _FunctionTypeMirror_parameters(reflectee)
       native "FunctionTypeMirror_parameters";
 }
 
@@ -1017,7 +1017,7 @@
   static dynamic _MethodMirror_return_type(reflectee)
       native "MethodMirror_return_type";
 
-  static List<MethodMirror> _MethodMirror_parameters(reflectee)
+  List<ParameterMirror> _MethodMirror_parameters(reflectee)
       native "MethodMirror_parameters";
 }
 
@@ -1065,14 +1065,22 @@
 
 class _LocalParameterMirrorImpl extends _LocalVariableMirrorImpl
     implements ParameterMirror {
-  _LocalParameterMirrorImpl(this._reflectee,
+  _LocalParameterMirrorImpl(reflectee,
+                            String simpleName,
+                            DeclarationMirror owner,
                             this._position,
-                            this.isOptional)
-      : super(null, '<TODO:unnamed>', null, null, false, false);
+                            this.isOptional,
+                            this.isNamed)
+      : super(reflectee,
+              simpleName,
+              owner,
+              null,  // We override the type.
+              false, // isStatic does not apply.
+              false);  // TODO(12196): Not yet implemented.
 
-  final _MirrorReference _reflectee;
   final int _position;
   final bool isOptional;
+  final bool isNamed;
 
   String get defaultValue {
     throw new UnimplementedError(
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index 8ef62a9..e2b4933 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -70,4 +70,8 @@
   }
 
   int get _cid native "Object_cid";
+
+  _leftShiftWithMask32(count, mask)  {
+    return (this << count) & mask;
+  }
 }
diff --git a/runtime/lib/string_buffer_patch.dart b/runtime/lib/string_buffer_patch.dart
index 2d1eb50..2d1acb5 100644
--- a/runtime/lib/string_buffer_patch.dart
+++ b/runtime/lib/string_buffer_patch.dart
@@ -47,7 +47,7 @@
     _length += str.length;
   }
 
-  /* patch */ writeCharCode(int charCode) {
+  /* patch */ void writeCharCode(int charCode) {
     if (charCode <= 0xFFFF) {
       if (charCode < 0) {
         throw new RangeError.range(charCode, 0, 0x10FFFF);
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 67e2d09..dbcefa0 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -54,15 +54,16 @@
 # Skip until we stabilize language tests.
 *: Skip
 
-[ $arch == mips ]
-*: Skip
-
 [ $arch == simarm ]
 dart/isolate_mirror_local_test: Skip
 
-[ $arch == simmips ]
+[ $arch == simmips || $arch == mips ]
 dart/isolate_mirror_local_test: Pass, Crash
-cc/FindCodeObject: Skip #  Relative offsets are too far
+
+[ $arch == mips ]
+cc/Sdc1Ldc1: Crash # Illegal instructions
+cc/Cop1CvtDL: Crash
+cc/Cop1CvtDL_neg: Crash
 
 # TODO(ajohnsen): Fix this as part of library changes.
 [ $compiler == none ]
diff --git a/runtime/tools/create_snapshot_bin.py b/runtime/tools/create_snapshot_bin.py
index db948a1..27eb5c4 100755
--- a/runtime/tools/create_snapshot_bin.py
+++ b/runtime/tools/create_snapshot_bin.py
@@ -73,7 +73,7 @@
     return 1
 
   # Setup arguments to the snapshot generator binary.
-  script_args = ["--error_on_malformed_type"]
+  script_args = ["--error_on_malformed_type", "--error_on_bad_override"]
 
   # First setup the snapshot output filename.
   script_args.append(''.join([ "--snapshot=", options.output_bin ]))
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index f935546..063470e 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -244,6 +244,11 @@
 }
 
 
+const char* BinaryOpWithMask32Node::Name() const {
+  return Token::Str(kind());
+}
+
+
 bool BinaryOpNode::IsPotentiallyConst() const {
   switch (kind_) {
     case Token::kADD:
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 0af0f3e..57e11b0 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -21,6 +21,7 @@
   V(TypeNode, "type")                                                          \
   V(AssignableNode, "assignable")                                              \
   V(BinaryOpNode, "binop")                                                     \
+  V(BinaryOpWithMask32Node, "binop with mask 32")                              \
   V(ComparisonNode, "compare")                                                 \
   V(UnaryOpNode, "unaryop")                                                    \
   V(ConditionalExprNode, "?:")                                                 \
@@ -579,6 +580,12 @@
   AstNode* left() const { return left_; }
   AstNode* right() const { return right_; }
 
+  virtual bool has_mask32() const { return false; }
+  virtual int64_t mask32() const {
+    UNREACHABLE();
+    return 0;
+  }
+
   virtual void VisitChildren(AstNodeVisitor* visitor) const {
     left()->Visit(visitor);
     right()->Visit(visitor);
@@ -601,6 +608,37 @@
 };
 
 
+class BinaryOpWithMask32Node : public BinaryOpNode {
+ public:
+  BinaryOpWithMask32Node(intptr_t token_pos,
+                         Token::Kind kind_value,
+                         AstNode* left,
+                         AstNode* right,
+                         int64_t mask32)
+      : BinaryOpNode(token_pos, kind_value, left, right), mask32_(mask32) {
+    ASSERT(mask32 >= 0 && Utils::IsUint(32, mask32));
+    ASSERT((kind_value != Token::kAND) && (kind_value != Token::kOR));
+  }
+
+  // The optional 32-bit mask must be a an unsigned 32-bit value.
+  virtual bool has_mask32() const { return true; }
+  virtual int64_t mask32() const {
+    ASSERT(has_mask32());
+    return mask32_;
+  }
+
+  virtual const char* Name() const;
+  DECLARE_COMMON_NODE_FUNCTIONS(BinaryOpWithMask32Node);
+
+ private:
+  // Optional unsigned 32 bit mask applied on result. No mask: -1.
+  const int64_t mask32_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryOpWithMask32Node);
+};
+
+
+
 class UnaryOpNode : public AstNode {
  public:
   // Returns optimized version, e.g., for ('-' '1') ('-1') literal is returned.
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index db100d7..79006b5 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -168,6 +168,14 @@
 }
 
 
+void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
+  OS::Print("(%s ", node->Name());
+  node->VisitChildren(this);
+  OS::Print(" & 0x%"Px64"", node->mask32());
+  OS::Print(")");
+}
+
+
 void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) {
   VisitGenericAstNode(node);
 }
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 0cf705f..60c4f54 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -22,6 +22,8 @@
   V(Object_as, 4)                                                              \
   V(Object_cid, 1)                                                             \
   V(Function_apply, 2)                                                         \
+  V(FunctionImpl_equals, 2)                                                    \
+  V(FunctionImpl_hashCode, 1)                                                  \
   V(InvocationMirror_invoke, 4)                                                \
   V(AbstractType_toString, 1)                                                  \
   V(Identical_comparison, 2)                                                   \
@@ -36,6 +38,7 @@
   V(Integer_greaterThanFromInteger, 2)                                         \
   V(Integer_equalToInteger, 2)                                                 \
   V(Integer_parse, 1)                                                          \
+  V(Integer_leftShiftWithMask32, 3)                                            \
   V(ReceivePortImpl_factory, 1)                                                \
   V(ReceivePortImpl_closeInternal, 1)                                          \
   V(SendPortImpl_sendInternal_, 3)                                             \
@@ -271,10 +274,10 @@
   V(TypeVariableMirror_upper_bound, 1)                                         \
   V(DeclarationMirror_metadata, 1)                                             \
   V(FunctionTypeMirror_call_method, 2)                                         \
-  V(FunctionTypeMirror_parameters, 1)                                          \
+  V(FunctionTypeMirror_parameters, 2)                                          \
   V(FunctionTypeMirror_return_type, 1)                                         \
   V(MethodMirror_owner, 1)                                                     \
-  V(MethodMirror_parameters, 1)                                                \
+  V(MethodMirror_parameters, 2)                                                \
   V(MethodMirror_return_type, 1)                                               \
   V(ParameterMirror_type, 2)                                                   \
   V(TypedefMirror_referent, 1)                                                 \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 25fb423..f59a048 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -14,6 +14,8 @@
 
 namespace dart {
 
+DEFINE_FLAG(bool, error_on_bad_override, false,
+            "Report error for bad overrides.");
 DEFINE_FLAG(bool, error_on_malformed_type, false,
             "Report error for malformed types.");
 DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes.");
@@ -50,7 +52,7 @@
     cls = class_table.At(cid);
     ASSERT(!cls.IsNull());
     array = cls.functions();
-    intptr_t num_functions = array.IsNull() ? 0 : array.Length();
+    const intptr_t num_functions = array.IsNull() ? 0 : array.Length();
     for (intptr_t f = 0; f < num_functions; f++) {
       function ^= array.At(f);
       ASSERT(!function.IsNull());
@@ -140,9 +142,6 @@
     // First resolve all superclasses.
     for (intptr_t i = 0; i < class_array.Length(); i++) {
       cls ^= class_array.At(i);
-      if (FLAG_trace_class_finalization) {
-        OS::Print("Resolving super and interfaces: %s\n", cls.ToCString());
-      }
       GrowableArray<intptr_t> visited_interfaces;
       ResolveSuperTypeAndInterfaces(cls, &visited_interfaces);
     }
@@ -308,7 +307,8 @@
     if (visited_factories.At(i) == factory.raw()) {
       // A redirection cycle is reported as a compile-time error.
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, factory.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, factory.token_pos(),
                   "factory '%s' illegally redirects to itself",
                   String::Handle(factory.name()).ToCString());
     }
@@ -382,25 +382,27 @@
     return;
   }
 
-  // Verify that the target is compatible with the redirecting factory.
-  if (!target.HasCompatibleParametersWith(factory)) {
-    type = NewFinalizedMalformedType(
-        Error::Handle(),  // No previous error.
-        cls,
-        factory.token_pos(),
-        "constructor '%s' has incompatible parameters with "
-        "redirecting factory '%s'",
-        String::Handle(target.name()).ToCString(),
-        String::Handle(factory.name()).ToCString());
-    factory.SetRedirectionType(type);
-    ASSERT(factory.RedirectionTarget() == Function::null());
-    return;
+  if (FLAG_error_on_bad_override) {
+    // Verify that the target is compatible with the redirecting factory.
+    Error& error = Error::Handle();
+    if (!target.HasCompatibleParametersWith(factory, &error)) {
+      type = NewFinalizedMalformedType(
+          error, target_class, target.token_pos(),
+          "constructor '%s' has incompatible parameters with "
+          "redirecting factory '%s'",
+          String::Handle(target.name()).ToCString(),
+          String::Handle(factory.name()).ToCString());
+      factory.SetRedirectionType(type);
+      ASSERT(factory.RedirectionTarget() == Function::null());
+      return;
+    }
   }
 
   // Verify that the target is const if the redirecting factory is const.
   if (factory.is_const() && !target.is_const()) {
-    const Script& script = Script::Handle(cls.script());
-    ReportError(script, factory.token_pos(),
+    const Script& script = Script::Handle(target_class.script());
+    ReportError(Error::Handle(),  // No previous error.
+                script, target.token_pos(),
                 "constructor '%s' must be const as required by redirecting"
                 "const factory '%s'",
                 String::Handle(target.name()).ToCString(),
@@ -499,7 +501,7 @@
   const AbstractTypeArguments& arguments =
       AbstractTypeArguments::Handle(type.arguments());
   if (!arguments.IsNull()) {
-    intptr_t num_arguments = arguments.Length();
+    const intptr_t num_arguments = arguments.Length();
     AbstractType& type_argument = AbstractType::Handle();
     for (intptr_t i = 0; i < num_arguments; i++) {
       type_argument = arguments.TypeAt(i);
@@ -768,7 +770,7 @@
   AbstractTypeArguments& arguments =
       AbstractTypeArguments::Handle(parameterized_type.arguments());
   if (!arguments.IsNull()) {
-    intptr_t num_arguments = arguments.Length();
+    const intptr_t num_arguments = arguments.Length();
     AbstractType& type_argument = AbstractType::Handle();
     for (intptr_t i = 0; i < num_arguments; i++) {
       type_argument = arguments.TypeAt(i);
@@ -795,7 +797,8 @@
     if (FLAG_error_on_malformed_type) {
       const Script& script = Script::Handle(cls.script());
       const String& type_class_name = String::Handle(type_class.Name());
-      ReportError(script, parameterized_type.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, parameterized_type.token_pos(),
                   "wrong number of type arguments for class '%s'",
                   type_class_name.ToCString());
     }
@@ -1028,7 +1031,7 @@
   AbstractType& type = AbstractType::Handle();
   String& name = String::Handle();
   Class& super_class = Class::Handle();
-  intptr_t num_fields = array.Length();
+  const intptr_t num_fields = array.Length();
   for (intptr_t i = 0; i < num_fields; i++) {
     field ^= array.At(i);
     type = field.type();
@@ -1042,7 +1045,8 @@
         const String& class_name = String::Handle(cls.Name());
         const String& super_class_name = String::Handle(super_class.Name());
         const Script& script = Script::Handle(cls.script());
-        ReportError(script, field.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, field.token_pos(),
                     "static field '%s' of class '%s' conflicts with "
                     "instance member '%s' of super class '%s'",
                     name.ToCString(),
@@ -1058,7 +1062,8 @@
         const String& class_name = String::Handle(cls.Name());
         const String& super_class_name = String::Handle(super_class.Name());
         const Script& script = Script::Handle(cls.script());
-        ReportError(script, field.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, field.token_pos(),
                     "field '%s' of class '%s' conflicts with method '%s' "
                     "of super class '%s'",
                     name.ToCString(),
@@ -1067,8 +1072,7 @@
                     super_class_name.ToCString());
       }
     }
-    if ((FLAG_enable_type_checks || FLAG_error_on_malformed_type) &&
-        field.is_static() && field.is_const() &&
+    if (field.is_static() && (field.is_const() || field.is_final()) &&
         (field.value() != Object::null()) &&
         (field.value() != Object::sentinel().raw())) {
       // The parser does not preset the value if the type is a type parameter or
@@ -1085,22 +1089,42 @@
            !const_value.IsInstanceOf(type,
                                      AbstractTypeArguments::Handle(),
                                      &malformed_error))) {
-        // If the failure is due to a malformed type error, display it instead.
-        if (!malformed_error.IsNull()) {
-          ReportError(malformed_error);
-        } else {
+        if (FLAG_error_on_malformed_type) {
           const AbstractType& const_value_type = AbstractType::Handle(
               const_value.GetType());
           const String& const_value_type_name = String::Handle(
               const_value_type.UserVisibleName());
           const String& type_name = String::Handle(type.UserVisibleName());
           const Script& script = Script::Handle(cls.script());
-          ReportError(script, field.token_pos(),
-                      "error initializing const field '%s': type '%s' is not a "
-                      "subtype of type '%s'",
+          ReportError(malformed_error, script, field.token_pos(),
+                      "error initializing static %s field '%s': "
+                      "type '%s' is not a subtype of type '%s'",
+                      field.is_const() ? "const" : "final",
                       name.ToCString(),
                       const_value_type_name.ToCString(),
                       type_name.ToCString());
+        } else {
+          // Do not report an error yet, even in checked mode, since the field
+          // may not actually be used.
+          // Also, we may be generating a snapshot in production mode that will
+          // later be executed in checked mode, in which case an error needs to
+          // be reported, should the field be accessed.
+          // Therefore, we undo the optimization performed by the parser, i.e.
+          // we create an implicit static final getter and reset the field value
+          // to the sentinel value.
+          const String& getter_name = String::Handle(Field::GetterSymbol(name));
+          const Function& getter = Function::Handle(
+              Function::New(getter_name,
+                            RawFunction::kImplicitStaticFinalGetter,
+                            /* is_static = */ true,
+                            /* is_const = */ field.is_const(),
+                            /* is_abstract = */ false,
+                            /* is_external = */ false,
+                            cls,
+                            field.token_pos()));
+          getter.set_result_type(type);
+          cls.AddFunction(getter);
+          field.set_value(Instance::Handle(Object::sentinel().raw()));
         }
       }
     }
@@ -1121,8 +1145,9 @@
   array = cls.functions();
   Function& function = Function::Handle();
   Function& overridden_function = Function::Handle();
-  intptr_t num_functions = array.Length();
+  const intptr_t num_functions = array.Length();
   String& function_name = String::Handle();
+  Error& error = Error::Handle();
   for (intptr_t i = 0; i < num_functions; i++) {
     function ^= array.At(i);
     ResolveAndFinalizeSignature(cls, function);
@@ -1133,7 +1158,8 @@
         const String& class_name = String::Handle(cls.Name());
         const String& super_class_name = String::Handle(super_class.Name());
         const Script& script = Script::Handle(cls.script());
-        ReportError(script, function.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, function.token_pos(),
                     "static function '%s' of class '%s' conflicts with "
                     "instance member '%s' of super class '%s'",
                     function_name.ToCString(),
@@ -1143,17 +1169,19 @@
       }
       // The function may be a still unresolved redirecting factory. Do not yet
       // try to resolve it in order to avoid cycles in class finalization.
-    } else {
+    } else if (FLAG_error_on_bad_override && !function.IsConstructor()) {
+      // A constructor cannot override anything.
       for (int i = 0; i < interfaces.Length(); i++) {
         super_class ^= interfaces.At(i);
         overridden_function = super_class.LookupDynamicFunction(function_name);
         if (!overridden_function.IsNull() &&
-            !function.HasCompatibleParametersWith(overridden_function)) {
+            !function.HasCompatibleParametersWith(overridden_function,
+                                                  &error)) {
           // Function types are purposely not checked for subtyping.
           const String& class_name = String::Handle(cls.Name());
           const String& super_class_name = String::Handle(super_class.Name());
           const Script& script = Script::Handle(cls.script());
-          ReportError(script, function.token_pos(),
+          ReportError(error, script, function.token_pos(),
                       "class '%s' overrides function '%s' of super class '%s' "
                       "with incompatible parameters",
                       class_name.ToCString(),
@@ -1169,7 +1197,8 @@
         const String& class_name = String::Handle(cls.Name());
         const String& super_class_name = String::Handle(super_class.Name());
         const Script& script = Script::Handle(cls.script());
-        ReportError(script, function.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, function.token_pos(),
                     "getter '%s' of class '%s' conflicts with "
                     "function '%s' of super class '%s'",
                     name.ToCString(),
@@ -1186,7 +1215,8 @@
         const String& class_name = String::Handle(cls.Name());
         const String& super_class_name = String::Handle(super_class.Name());
         const Script& script = Script::Handle(cls.script());
-        ReportError(script, function.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, function.token_pos(),
                     "function '%s' of class '%s' conflicts with "
                     "getter '%s' of super class '%s'",
                     function_name.ToCString(),
@@ -1240,7 +1270,8 @@
       // TODO(hausner): handle type bounds.
       if (!param_bound.IsObjectType()) {
         const Script& script = Script::Handle(mixapp_class.script());
-        ReportError(script, param.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, param.token_pos(),
                     "type parameter '%s': type bounds not yet"
                     " implemented for mixins\n",
                     param_name.ToCString());
@@ -1282,7 +1313,8 @@
       // TODO(hausner): handle type bounds.
       if (!param_bound.IsObjectType()) {
         const Script& script = Script::Handle(mixapp_class.script());
-        ReportError(script, param.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, param.token_pos(),
                     "type parameter '%s': type bounds not yet"
                     " implemented for mixins\n",
                     param_name.ToCString());
@@ -1333,7 +1365,8 @@
   if (!mixin_super_type.IsObjectType()) {
     const Script& script = Script::Handle(cls.script());
     const String& class_name = String::Handle(mixin_cls.Name());
-    ReportError(script, cls.token_pos(),
+    ReportError(Error::Handle(),  // No previous error.
+                script, cls.token_pos(),
                 "mixin class %s must extend class Object",
                 class_name.ToCString());
   }
@@ -1359,7 +1392,7 @@
   const String& super_name = String::Handle(super_class.Name());
   const Type& dynamic_type = Type::Handle(Type::DynamicType());
   const Array& functions = Array::Handle(super_class.functions());
-  intptr_t num_functions = functions.Length();
+  const intptr_t num_functions = functions.Length();
   Function& func = Function::Handle();
   for (intptr_t i = 0; i < num_functions; i++) {
     func ^= functions.At(i);
@@ -1437,7 +1470,8 @@
       // A mixin class must not have explicit constructors.
       if (!func.IsImplicitConstructor()) {
         const Script& script = Script::Handle(isolate, cls.script());
-        ReportError(script, cls.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, cls.token_pos(),
                     "mixin class %s must not have constructors\n",
                     String::Handle(isolate, mixin_cls.Name()).ToCString());
       }
@@ -1489,7 +1523,8 @@
   if (!IsSuperCycleFree(cls)) {
     const String& name = String::Handle(cls.Name());
     const Script& script = Script::Handle(cls.script());
-    ReportError(script, cls.token_pos(),
+    ReportError(Error::Handle(),  // No previous error.
+                script, cls.token_pos(),
                 "class '%s' has a cycle in its superclass relationship",
                 name.ToCString());
   }
@@ -1523,14 +1558,12 @@
     if (!IsAliasCycleFree(cls, &visited_aliases)) {
       const String& name = String::Handle(cls.Name());
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, cls.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, cls.token_pos(),
                   "typedef '%s' illegally refers to itself",
                   name.ToCString());
     }
     cls.set_is_type_finalized();
-    // Signature classes extend Object. No need to add this class to the direct
-    // subclasses of Object.
-    ASSERT(super_type.IsNull() || super_type.IsObjectType());
 
     // The type parameters of signature classes may have bounds.
     FinalizeUpperBounds(cls);
@@ -1561,7 +1594,8 @@
     ASSERT(super_type.IsNull() || super_type.IsFinalized());
     if (!super_type.IsNull() && interface_type.Equals(super_type)) {
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, cls.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, cls.token_pos(),
                   "super type '%s' may not be listed in "
                   "implements clause of class '%s'",
                   String::Handle(super_type.Name()).ToCString(),
@@ -1571,7 +1605,8 @@
       seen_interf ^= interface_types.At(j);
       if (interface_type.Equals(seen_interf)) {
         const Script& script = Script::Handle(cls.script());
-        ReportError(script, cls.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, cls.token_pos(),
                     "interface '%s' appears twice in "
                     "implements clause of class '%s'",
                     String::Handle(interface_type.Name()).ToCString(),
@@ -1591,9 +1626,15 @@
     ASSERT(!super_class.IsNull());
     super_class.AddDirectSubclass(cls);
   }
-  // Top level classes are parsed eagerly so just finalize it.
+  // A top level class is parsed eagerly so just finalize it.
   if (cls.IsTopLevel()) {
     FinalizeClass(cls);
+  } else {
+    // This class should not contain any fields or functions yet, because it has
+    // not been compiled yet. Since 'ResolveAndFinalizeMemberTypes(cls)' has not
+    // been called yet, unfinalized member types could choke the snapshotter.
+    ASSERT(Array::Handle(cls.fields()).Length() == 0);
+    ASSERT(Array::Handle(cls.functions()).Length() == 0);
   }
 }
 
@@ -1619,6 +1660,17 @@
   }
   // Mark as parsed and finalized.
   cls.Finalize();
+  // Mixin typedef classes may still lack their implicit constructor.
+  // TODO(regis): Implement mixin typedefs with an alias class.
+  if (cls.is_synthesized_class() &&
+      (cls.functions() == Object::empty_array().raw())) {
+    Parser::AddImplicitConstructor(cls);
+  }
+  // Every class should have at least a constructor, unless it is a top level
+  // class or a signature class.
+  ASSERT(cls.IsTopLevel() ||
+         cls.IsSignatureClass() ||
+         (Array::Handle(cls.functions()).Length() > 0));
   // Resolve and finalize all member types.
   ResolveAndFinalizeMemberTypes(cls);
   // Run additional checks after all types are finalized.
@@ -1715,23 +1767,26 @@
 }
 
 
-void ClassFinalizer::CollectTypeArguments(const Class& cls,
-                              const Type& type,
-                              const GrowableObjectArray& collected_args) {
+void ClassFinalizer::CollectTypeArguments(
+    const Class& cls,
+    const Type& type,
+    const GrowableObjectArray& collected_args) {
   ASSERT(type.HasResolvedTypeClass());
   Class& type_class = Class::Handle(type.type_class());
   AbstractTypeArguments& type_args =
       AbstractTypeArguments::Handle(type.arguments());
-  intptr_t num_type_parameters = type_class.NumTypeParameters();
-  intptr_t num_type_arguments = type_args.IsNull() ? 0 : type_args.Length();
+  const intptr_t num_type_parameters = type_class.NumTypeParameters();
+  const intptr_t num_type_arguments =
+      type_args.IsNull() ? 0 : type_args.Length();
   AbstractType& arg = AbstractType::Handle();
   if (num_type_arguments > 0) {
     if (num_type_arguments != num_type_parameters) {
       const Script& script = Script::Handle(cls.script());
       const String& type_class_name = String::Handle(type_class.Name());
-      ReportError(script, type.token_pos(),
-          "wrong number of type arguments for class '%s'",
-          type_class_name.ToCString());
+      ReportError(Error::Handle(),  // No previous error.
+                  script, type.token_pos(),
+                  "wrong number of type arguments for class '%s'",
+                  type_class_name.ToCString());
     }
     for (int i = 0; i < num_type_arguments; i++) {
       arg = type_args.TypeAt(i);
@@ -1804,13 +1859,17 @@
 void ClassFinalizer::ResolveSuperTypeAndInterfaces(
     const Class& cls, GrowableArray<intptr_t>* visited) {
   ASSERT(visited != NULL);
+  if (FLAG_trace_class_finalization) {
+    OS::Print("Resolving super and interfaces: %s\n", cls.ToCString());
+  }
   const intptr_t cls_index = cls.id();
   for (int i = 0; i < visited->length(); i++) {
     if ((*visited)[i] == cls_index) {
       // We have already visited class 'cls'. We found a cycle.
       const String& class_name = String::Handle(cls.Name());
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, cls.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, cls.token_pos(),
                   "cyclic reference found for class '%s'",
                   class_name.ToCString());
     }
@@ -1847,12 +1906,21 @@
   }
   if (super_type.IsDynamicType()) {
     const Script& script = Script::Handle(cls.script());
-    ReportError(script, cls.token_pos(),
+    ReportError(Error::Handle(),  // No previous error.
+                script, cls.token_pos(),
                 "class '%s' may not extend 'dynamic'",
                 String::Handle(cls.Name()).ToCString());
   }
-
   interface_class = super_type.type_class();
+  if (interface_class.IsSignatureClass()) {
+    const Script& script = Script::Handle(cls.script());
+    ReportError(Error::Handle(),  // No previous error.
+                script, cls.token_pos(),
+                "class '%s' may not extend function type alias '%s'",
+                String::Handle(cls.Name()).ToCString(),
+                String::Handle(super_type.UserVisibleName()).ToCString());
+  }
+
   // If cls belongs to core lib or to core lib's implementation, restrictions
   // about allowed interfaces are lifted.
   if (!cls_belongs_to_core_lib) {
@@ -1880,7 +1948,6 @@
       CLASS_LIST_TYPED_DATA(DO_NOT_EXTEND_TYPED_DATA_CLASSES)
 #undef DO_NOT_EXTEND_TYPED_DATA_CLASSES
       case kByteDataViewCid:
-      case kDartFunctionCid:
       case kWeakPropertyCid:
         is_error = true;
         break;
@@ -1896,7 +1963,8 @@
     }
     if (is_error) {
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, cls.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, cls.token_pos(),
                   "'%s' is not allowed to extend '%s'",
                   String::Handle(cls.Name()).ToCString(),
                   String::Handle(interface_class.Name()).ToCString());
@@ -1915,14 +1983,16 @@
     }
     if (interface.IsDynamicType()) {
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, cls.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, cls.token_pos(),
                   "'dynamic' may not be used as interface");
     }
     interface_class = interface.type_class();
     if (interface_class.IsSignatureClass()) {
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, cls.token_pos(),
-                  "'%s' is used where an interface or class name is expected",
+      ReportError(Error::Handle(),  // No previous error.
+                  script, cls.token_pos(),
+                  "function type alias '%s' may not be used as interface",
                   String::Handle(interface_class.Name()).ToCString());
     }
     // Verify that unless cls belongs to core lib, it cannot extend or implement
@@ -1935,10 +2005,10 @@
           interface.IsIntType() ||
           interface.IsDoubleType() ||
           interface.IsStringType() ||
-          (interface.IsFunctionType() && !cls.IsSignatureClass()) ||
           interface.IsDynamicType()) {
         const Script& script = Script::Handle(cls.script());
-        ReportError(script, cls.token_pos(),
+        ReportError(Error::Handle(),  // No previous error.
+                    script, cls.token_pos(),
                     "'%s' is not allowed to extend or implement '%s'",
                     String::Handle(cls.Name()).ToCString(),
                     String::Handle(interface_class.Name()).ToCString());
@@ -1966,7 +2036,8 @@
       const String& class_name = String::Handle(cls.Name());
       const String& field_name = String::Handle(field.name());
       const Script& script = Script::Handle(cls.script());
-      ReportError(script, field.token_pos(),
+      ReportError(Error::Handle(),  // No previous error.
+                  script, field.token_pos(),
                   "const class '%s' has non-final field '%s'",
                   class_name.ToCString(), field_name.ToCString());
     }
@@ -2091,13 +2162,19 @@
 }
 
 
-void ClassFinalizer::ReportError(const Script& script,
+void ClassFinalizer::ReportError(const Error& prev_error,
+                                 const Script& script,
                                  intptr_t token_pos,
                                  const char* format, ...) {
   va_list args;
   va_start(args, format);
-  const Error& error = Error::Handle(
-      Parser::FormatError(script, token_pos, "Error", format, args));
+  Error& error = Error::Handle();
+  if (prev_error.IsNull()) {
+    error ^= Parser::FormatError(script, token_pos, "Error", format, args);
+  } else {
+    error ^= Parser::FormatErrorWithAppend(
+        prev_error, script, token_pos, "Error", format, args);
+  }
   va_end(args);
   ReportError(error);
 }
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index 809adee..cb9df49 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -76,8 +76,13 @@
   // in the object store.
   static bool FinalizePendingClasses();
 
+  // Finalize the types appearing in the declaration of class 'cls', i.e. its
+  // type parameters and their upper bounds, its super type and interfaces.
+  // Note that the fields and functions have not been parsed yet (unless cls
+  // is an anonymous top level class).
   static void FinalizeTypesInClass(const Class& cls);
 
+  // Finalize the class including its fields and functions.
   static void FinalizeClass(const Class& cls);
 
   // Verify that the classes have been properly prefinalized. This is
@@ -141,9 +146,10 @@
                                   const char* format,
                                   va_list args);
   static void ReportError(const Error& error);
-  static void ReportError(const Script& script,
+  static void ReportError(const Error& prev_error,
+                          const Script& script,
                           intptr_t token_index,
-                          const char* format, ...) PRINTF_ATTRIBUTE(3, 4);
+                          const char* format, ...) PRINTF_ATTRIBUTE(4, 5);
   static void ReportError(const char* format, ...) PRINTF_ATTRIBUTE(1, 2);
 
   // Verify implicit offsets recorded in the VM for direct access to fields of
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 3299340..aa88e83 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -26,6 +26,7 @@
 #include "vm/object_store.h"
 #include "vm/port.h"
 #include "vm/resolver.h"
+#include "vm/reusable_handles.h"
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
 #include "vm/timer.h"
@@ -262,6 +263,12 @@
 }
 
 
+void Api::SetWeakHandleReturnValue(NativeArguments* args,
+                                   Dart_WeakPersistentHandle retval) {
+  args->SetReturnUnsafe(Api::UnwrapAsWeakPersistentHandle(retval)->raw());
+}
+
+
 // --- Handles ---
 
 DART_EXPORT bool Dart_IsError(Dart_Handle handle) {
@@ -1132,7 +1139,7 @@
 
 
 DART_EXPORT bool Dart_IsNull(Dart_Handle object) {
-  return Api::ClassId(object) == kNullCid;
+  return Api::UnwrapHandle(object) == Object::null();
 }
 
 
@@ -1842,6 +1849,28 @@
 }
 
 
+DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle object,
+                                                 intptr_t* char_size,
+                                                 intptr_t* str_len,
+                                                 void** peer) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const String& str = Api::UnwrapStringHandle(isolate, object);
+  if (str.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, object, String);
+  }
+  if (str.IsExternal()) {
+    *peer = str.GetPeer();
+    ASSERT(*peer != NULL);
+  } else {
+    *peer = NULL;
+  }
+  *char_size = str.CharSize();
+  *str_len = str.Length();
+  return Api::Success();
+}
+
+
 // --- Lists ---
 
 DART_EXPORT Dart_Handle Dart_NewList(intptr_t length) {
@@ -3623,12 +3652,15 @@
   return Api::Success();
 }
 
+
 DART_EXPORT Dart_Handle Dart_GetNativeReceiver(Dart_NativeArguments args,
                                                intptr_t* value) {
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
   Isolate* isolate = arguments->isolate();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, arguments->NativeArgAt(0));
+  CHECK_ISOLATE(isolate);
+  ReusableObjectHandleScope reused_obj_handle(isolate);
+  Object& obj = reused_obj_handle.Handle();
+  obj = arguments->NativeArgAt(0);
   intptr_t cid = obj.GetClassId();
   if (cid <= kNumPredefinedCids) {
     if (cid == kNullCid) {
@@ -3648,6 +3680,31 @@
 }
 
 
+DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args,
+                                                     int arg_index,
+                                                     void** peer) {
+  NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+  Isolate* isolate = arguments->isolate();
+  CHECK_ISOLATE(isolate);
+  ReusableObjectHandleScope reused_obj_handle(isolate);
+  Object& obj = reused_obj_handle.Handle();
+  obj = arguments->NativeArgAt(arg_index);
+  intptr_t cid = obj.GetClassId();
+  if (RawObject::IsExternalStringClassId(cid)) {
+    const String& str = String::Cast(obj);
+    *peer = str.GetPeer();
+    ASSERT(*peer != NULL);
+    return Api::Success();
+  }
+  *peer = NULL;
+  if (RawObject::IsStringClassId(cid)) {
+    return Api::NewHandle(isolate, obj.raw());
+  }
+  return Api::NewError("%s expects argument to be of"
+                       " type String.", CURRENT_FUNC);
+}
+
+
 DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
                                      Dart_Handle retval) {
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
@@ -3663,6 +3720,18 @@
 }
 
 
+DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args,
+                                               Dart_WeakPersistentHandle rval) {
+  NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+  Isolate* isolate = arguments->isolate();
+  CHECK_ISOLATE(isolate);
+  ASSERT(isolate->api_state() != NULL &&
+         (isolate->api_state()->IsValidWeakPersistentHandle(rval) ||
+          isolate->api_state()->IsValidPrologueWeakPersistentHandle(rval)));
+  Api::SetWeakHandleReturnValue(arguments, rval);
+}
+
+
 DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
                                             bool retval) {
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 95b1b1a..d549b8f 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -206,6 +206,8 @@
   static void SetDoubleReturnValue(NativeArguments* args, double retval) {
     args->SetReturnUnsafe(Double::New(retval));
   }
+  static void SetWeakHandleReturnValue(NativeArguments* args,
+                                       Dart_WeakPersistentHandle retval);
 
  private:
   // Thread local key used by the API. Currently holds the current
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index dc3017c3..d73aa85 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -542,6 +542,16 @@
   intptr_t len = -1;
   EXPECT_VALID(Dart_StringLength(latin1str, &len));
   EXPECT_EQ(4, len);
+  intptr_t char_size;
+  intptr_t str_len;
+  void* peer;
+  EXPECT_VALID(Dart_StringGetProperties(latin1str,
+                                        &char_size,
+                                        &str_len,
+                                        &peer));
+  EXPECT_EQ(1, char_size);
+  EXPECT_EQ(4, str_len);
+  EXPECT(!peer);
 
   uint8_t data8[] = { 'o', 'n', 'e', 0x7F };
 
@@ -562,10 +572,17 @@
   }
 
   Dart_Handle ext8 = Dart_NewExternalLatin1String(data8, ARRAY_SIZE(data8),
-                                                  NULL, NULL);
+                                                  data8, NULL);
   EXPECT_VALID(ext8);
   EXPECT(Dart_IsString(ext8));
   EXPECT(Dart_IsExternalString(ext8));
+  EXPECT_VALID(Dart_StringGetProperties(ext8,
+                                        &char_size,
+                                        &str_len,
+                                        &peer));
+  EXPECT_EQ(1, char_size);
+  EXPECT_EQ(4, str_len);
+  EXPECT_EQ(data8, peer);
 
   uint16_t data16[] = { 't', 'w', 'o', 0xFFFF };
 
@@ -574,12 +591,26 @@
   EXPECT(Dart_IsString(str16));
   EXPECT(!Dart_IsStringLatin1(str16));
   EXPECT(!Dart_IsExternalString(str16));
+  EXPECT_VALID(Dart_StringGetProperties(str16,
+                                        &char_size,
+                                        &str_len,
+                                        &peer));
+  EXPECT_EQ(2, char_size);
+  EXPECT_EQ(4, str_len);
+  EXPECT(!peer);
 
   Dart_Handle ext16 = Dart_NewExternalUTF16String(data16, ARRAY_SIZE(data16),
-                                                  NULL, NULL);
+                                                  data16, NULL);
   EXPECT_VALID(ext16);
   EXPECT(Dart_IsString(ext16));
   EXPECT(Dart_IsExternalString(ext16));
+  EXPECT_VALID(Dart_StringGetProperties(ext16,
+                                        &char_size,
+                                        &str_len,
+                                        &peer));
+  EXPECT_EQ(2, char_size);
+  EXPECT_EQ(4, str_len);
+  EXPECT_EQ(data16, peer);
 
   int32_t data32[] = { 'f', 'o', 'u', 'r', 0x10FFFF };
 
@@ -3423,6 +3454,9 @@
   // Invoke a function which returns an object of type NativeFields.
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
 
+  USE(result);
+#if 0
+  // TODO(12455) Need better validation.
   // We expect the test script to fail finalization with the error below:
   EXPECT(Dart_IsError(result));
   Dart_Handle expected_error = Dart_Error(
@@ -3431,6 +3465,7 @@
       "but library '%s' has no native resolvers",
       TestCase::url());
   EXPECT_SUBSTRING(Dart_GetError(expected_error), Dart_GetError(result));
+#endif
 }
 
 
@@ -5302,7 +5337,7 @@
   "  final fvalue;\n"
   "  var _f;\n"
   "  callFunc(x, y) => x(y);\n"
-  "  external method(var value);\n"
+  "  external void method(var value);\n"
   "  get field => _field;\n"
   "}\n"
   "class B {\n"
@@ -5320,7 +5355,7 @@
   "  var _g;\n"
   "  A() : fvalue = 13;\n"
   "  get _field => _g;\n"
-  "  patch method(var value) {\n"
+  "  /*patch*/ void method(var value) {\n"
   "    int closeYourEyes(var eggs) { return eggs * -1; }\n"
   "    value = callFunc(closeYourEyes, value);\n"
   "    _g = value * 5;\n"
@@ -7105,8 +7140,15 @@
   Dart_EnterScope();
   Dart_Handle str = Dart_GetNativeArgument(args, 0);
   EXPECT(Dart_IsString(str));
+  void* peer;
+  Dart_Handle str_arg = Dart_GetNativeStringArgument(args, 0, &peer);
+  EXPECT(Dart_IsString(str_arg));
+  EXPECT(!peer);
   intptr_t size = 0;
   EXPECT_VALID(Dart_StringStorageSize(str, &size));
+  intptr_t arg_size = 0;
+  EXPECT_VALID(Dart_StringStorageSize(str_arg, &arg_size));
+  EXPECT_EQ(size, arg_size);
   char* str_data = new char[size];
   Dart_Handle result =
       Dart_MakeExternalString(str,
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 109bb84..8ff2c10 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -201,51 +201,60 @@
   Function& func = Function::Handle();
   Code& code = Code::Handle();
   Smi& offset = Smi::Handle();
-  bool handler_found = false;
-  while (!frame->IsEntryFrame()) {
-    if (frame->IsDartFrame()) {
-      code = frame->LookupDartCode();
-      if (code.is_optimized()) {
-        // For optimized frames, extract all the inlined functions if any
-        // into the stack trace.
-        for (InlinedFunctionsIterator it(frame); !it.Done(); it.Advance()) {
-          func = it.function();
-          code = it.code();
-          uword pc = it.pc();
-          ASSERT(pc != 0);
-          ASSERT(code.EntryPoint() <= pc);
-          ASSERT(pc < (code.EntryPoint() + code.Size()));
+  bool dart_handler_found = false;
+  bool handler_pc_set = false;
+  while (frame != NULL) {
+    while (!frame->IsEntryFrame()) {
+      if (frame->IsDartFrame()) {
+        code = frame->LookupDartCode();
+        if (code.is_optimized()) {
+          // For optimized frames, extract all the inlined functions if any
+          // into the stack trace.
+          for (InlinedFunctionsIterator it(frame); !it.Done(); it.Advance()) {
+            func = it.function();
+            code = it.code();
+            uword pc = it.pc();
+            ASSERT(pc != 0);
+            ASSERT(code.EntryPoint() <= pc);
+            ASSERT(pc < (code.EntryPoint() + code.Size()));
+            if (ShouldShowFunction(func)) {
+              offset = Smi::New(pc - code.EntryPoint());
+              builder->AddFrame(func, code, offset, dart_handler_found);
+            }
+          }
+        } else {
+          offset = Smi::New(frame->pc() - code.EntryPoint());
+          func = code.function();
           if (ShouldShowFunction(func)) {
-            offset = Smi::New(pc - code.EntryPoint());
-            builder->AddFrame(func, code, offset, handler_found);
+            builder->AddFrame(func, code, offset, dart_handler_found);
           }
         }
-      } else {
-        offset = Smi::New(frame->pc() - code.EntryPoint());
-        func = code.function();
-        if (ShouldShowFunction(func)) {
-          builder->AddFrame(func, code, offset, handler_found);
+        if (!handler_pc_set && frame->FindExceptionHandler(handler_pc)) {
+          handler_pc_set = true;
+          *handler_sp = frame->sp();
+          *handler_fp = frame->fp();
+          dart_handler_found = true;
+          if (!builder->FullStacktrace()) {
+            return dart_handler_found;
+          }
         }
       }
-      if (!handler_found && frame->FindExceptionHandler(handler_pc)) {
-        *handler_sp = frame->sp();
-        *handler_fp = frame->fp();
-        handler_found = true;
-        if (!builder->FullStacktrace()) {
-          return handler_found;
-        }
+      frame = frames.NextFrame();
+      ASSERT(frame != NULL);
+    }
+    ASSERT(frame->IsEntryFrame());
+    if (!handler_pc_set) {
+      handler_pc_set = true;
+      *handler_pc = frame->pc();
+      *handler_sp = frame->sp();
+      *handler_fp = frame->fp();
+      if (!builder->FullStacktrace()) {
+        return dart_handler_found;
       }
     }
     frame = frames.NextFrame();
-    ASSERT(frame != NULL);
   }
-  ASSERT(frame->IsEntryFrame());
-  if (!handler_found) {
-    *handler_pc = frame->pc();
-    *handler_sp = frame->sp();
-    *handler_fp = frame->fp();
-  }
-  return handler_found;
+  return dart_handler_found;
 }
 
 
@@ -364,7 +373,7 @@
                                           &frame_builder);
   } else {
     const Field& stacktrace_field =
-        Field::Handle(LookupStacktraceField(incoming_exception));
+        Field::Handle(LookupStacktraceField(exception));
     bool full_stacktrace = !stacktrace_field.IsNull();
     RegularStacktraceBuilder frame_builder(full_stacktrace);
     handler_exists = FindExceptionHandler(&handler_pc,
@@ -396,8 +405,8 @@
       stacktrace.SetCatchStacktrace(catch_func_array,
                                     catch_code_array,
                                     catch_pc_offset_array);
-      if (incoming_exception.GetField(stacktrace_field) == Object::null()) {
-        incoming_exception.SetField(stacktrace_field, stacktrace);
+      if (exception.GetField(stacktrace_field) == Object::null()) {
+        exception.SetField(stacktrace_field, stacktrace);
       }
     }
     // TODO(5411263): At some point we can optimize by figuring out if a
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index f9c395c..c1717ec 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -983,12 +983,13 @@
   arguments->Add(push_left);
   arguments->Add(push_right);
   const String& name = String::ZoneHandle(Symbols::New(node->Name()));
+  const intptr_t kNumArgsChecked = 2;
   InstanceCallInstr* call = new InstanceCallInstr(node->token_pos(),
                                                   name,
                                                   node->kind(),
                                                   arguments,
                                                   Object::null_array(),
-                                                  2,
+                                                  kNumArgsChecked,
                                                   owner()->ic_data_array());
   ReturnDefinition(call);
 }
@@ -1044,6 +1045,54 @@
 }
 
 
+static const String& BinaryOpAndMaskName(BinaryOpNode* node) {
+  if (node->kind() == Token::kSHL) {
+    return PrivateCoreLibName(Symbols::_leftShiftWithMask32());
+  }
+  UNIMPLEMENTED();
+  return String::ZoneHandle();
+}
+
+
+// <Expression> :: BinaryOp { kind:  Token::Kind
+//                            left:  <Expression>
+//                            right: <Expression>
+//                            mask32: constant }
+void EffectGraphVisitor::VisitBinaryOpWithMask32Node(
+    BinaryOpWithMask32Node* node) {
+  ASSERT((node->kind() != Token::kAND) && (node->kind() != Token::kOR));
+  ValueGraphVisitor for_left_value(owner(), temp_index());
+  node->left()->Visit(&for_left_value);
+  Append(for_left_value);
+  PushArgumentInstr* push_left = PushArgument(for_left_value.value());
+
+  ValueGraphVisitor for_right_value(owner(), temp_index());
+  node->right()->Visit(&for_right_value);
+  Append(for_right_value);
+  PushArgumentInstr* push_right = PushArgument(for_right_value.value());
+
+  Value* mask_value = Bind(new ConstantInstr(
+      Integer::ZoneHandle(Integer::New(node->mask32(), Heap::kOld))));
+  PushArgumentInstr* push_mask = PushArgument(mask_value);
+
+  ZoneGrowableArray<PushArgumentInstr*>* arguments =
+      new ZoneGrowableArray<PushArgumentInstr*>(3);
+  arguments->Add(push_left);
+  arguments->Add(push_right);
+  // Call to special method 'BinaryOpAndMaskName(node)'.
+  arguments->Add(push_mask);
+  const intptr_t kNumArgsChecked = 2;
+  InstanceCallInstr* call = new InstanceCallInstr(node->token_pos(),
+                                                  BinaryOpAndMaskName(node),
+                                                  Token::kILLEGAL,
+                                                  arguments,
+                                                  Object::null_array(),
+                                                  kNumArgsChecked,
+                                                  owner()->ic_data_array());
+  ReturnDefinition(call);
+}
+
+
 void EffectGraphVisitor::BuildTypecheckPushArguments(
     intptr_t token_pos,
     PushArgumentInstr** push_instantiator_result,
@@ -3447,6 +3496,8 @@
                              push_arguments,
                              owner()->ic_data_array());
 }
+
+
 StaticCallInstr* EffectGraphVisitor::BuildThrowNoSuchMethodError(
     intptr_t token_pos,
     const Class& function_class,
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 9c6f259..353cc8b 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -20,21 +20,21 @@
 // (factory-name-symbol, result-cid, fingerprint).
 // TODO(srdjan): Store the values in the snapshot instead.
 #define RECOGNIZED_LIST_FACTORY_LIST(V)                                        \
-  V(ObjectArrayFactory, kArrayCid, 1149848530)                                 \
-  V(GrowableObjectArrayWithData, kGrowableObjectArrayCid, 569069682)           \
-  V(GrowableObjectArrayFactory, kGrowableObjectArrayCid, 1821003625)           \
-  V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 1139775342)                     \
-  V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 2065936658)                   \
-  V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 1420655937)     \
-  V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 1401847016)                   \
-  V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 967612741)                  \
-  V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 332168564)                    \
-  V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 966424258)                  \
-  V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 541618991)                    \
-  V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1085703705)                 \
-  V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1867705160)               \
-  V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 1691006880)               \
-  V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1739837241)           \
+  V(ObjectArrayFactory, kArrayCid, 712468799)                                  \
+  V(GrowableObjectArrayWithData, kGrowableObjectArrayCid, 917195627)           \
+  V(GrowableObjectArrayFactory, kGrowableObjectArrayCid, 1707369421)           \
+  V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 1340298556)                     \
+  V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 1775618642)                   \
+  V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 264668024)      \
+  V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 1095249987)                   \
+  V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 1275304272)                 \
+  V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 523449884)                    \
+  V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 458531362)                  \
+  V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 1753070829)                   \
+  V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1561660391)                 \
+  V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 245916452)                \
+  V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 368082071)                \
+  V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1674296969)           \
 
 
 // A class to collect the exits from an inlined function during graph
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index d1a8555..74137bc 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -397,6 +397,22 @@
     converted = new UnboxUint32x4Instr(use->CopyWithType(), deopt_id);
   } else if ((from == kUnboxedUint32x4) && (to == kTagged)) {
     converted = new BoxUint32x4Instr(use->CopyWithType());
+  } else {
+    const intptr_t deopt_id = (deopt_target != NULL) ?
+        deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
+    // We have failed to find a suitable conversion instruction.
+    // Insert a "dummy" conversion instruction with the correct
+    // "to" representation. The inserted instruction will trigger a
+    // a deoptimization if executed. See issue #12417 for a discussion.
+    if (to == kUnboxedDouble) {
+      converted = new UnboxDoubleInstr(use->CopyWithType(), deopt_id);
+    } else if (to == kUnboxedUint32x4) {
+      converted = new UnboxDoubleInstr(use->CopyWithType(), deopt_id);
+    } else if (to == kUnboxedFloat32x4) {
+      converted = new UnboxDoubleInstr(use->CopyWithType(), deopt_id);
+    } else if (to == kUnboxedMint) {
+      converted = new UnboxIntegerInstr(use->CopyWithType(), deopt_id);
+    }
   }
   ASSERT(converted != NULL);
   use->BindTo(converted);
@@ -1942,6 +1958,67 @@
   if ((class_ids[0] == kUint32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
     return TryInlineUint32x4Method(call, recognized_kind);
   }
+
+  if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) {
+    ASSERT(call->ArgumentCount() == 3);
+    ASSERT(ic_data.num_args_tested() == 2);
+    Definition* value = call->ArgumentAt(0);
+    Definition* count = call->ArgumentAt(1);
+    Definition* int32_mask = call->ArgumentAt(2);
+    if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+      if (ic_data.deopt_reason() == kDeoptShiftMintOp) {
+        return false;
+      }
+      // We cannot overflow. The input value must be a Smi
+      AddCheckSmi(value, call->deopt_id(), call->env(), call);
+      AddCheckSmi(count, call->deopt_id(), call->env(), call);
+      ASSERT(int32_mask->IsConstant());
+      const Integer& mask_literal = Integer::Cast(
+          int32_mask->AsConstant()->value());
+      const int64_t mask_value = mask_literal.AsInt64Value();
+      ASSERT(mask_value >= 0);
+      if (mask_value > Smi::kMaxValue) {
+        // The result will not be Smi.
+        return false;
+      }
+      BinarySmiOpInstr* left_shift =
+          new BinarySmiOpInstr(Token::kSHL,
+                               new Value(value), new Value(count),
+                               call->deopt_id());
+      left_shift->set_is_truncating(true);
+      if ((kBitsPerWord == 32) && (mask_value == 0xffffffffLL)) {
+        // No BIT_AND operation needed.
+        ReplaceCall(call, left_shift);
+      } else {
+        InsertBefore(call, left_shift, call->env(), Definition::kValue);
+        BinarySmiOpInstr* bit_and =
+            new BinarySmiOpInstr(Token::kBIT_AND,
+                                 new Value(left_shift), new Value(int32_mask),
+                                 call->deopt_id());
+        ReplaceCall(call, bit_and);
+      }
+      return true;
+    }
+
+    if (HasTwoMintOrSmi(ic_data) &&
+        HasOnlyOneSmi(ICData::Handle(ic_data.AsUnaryClassChecksForArgNr(1)))) {
+      if (!FlowGraphCompiler::SupportsUnboxedMints() ||
+          (ic_data.deopt_reason() == kDeoptShiftMintOp)) {
+        return false;
+      }
+      ShiftMintOpInstr* left_shift =
+          new ShiftMintOpInstr(Token::kSHL,
+                               new Value(value), new Value(count),
+                               call->deopt_id());
+      InsertBefore(call, left_shift, call->env(), Definition::kValue);
+      BinaryMintOpInstr* bit_and =
+          new BinaryMintOpInstr(Token::kBIT_AND,
+                                new Value(left_shift), new Value(int32_mask),
+                                call->deopt_id());
+      ReplaceCall(call, bit_and);
+      return true;
+    }
+  }
   return false;
 }
 
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 641b009..e71aba8 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -38,103 +38,105 @@
 // (class-name, function-name, recognized enum, fingerprint).
 // See intrinsifier for fingerprint computation.
 #define RECOGNIZED_LIST(V)                                                     \
-  V(::, identical, ObjectIdentical, 1018911876)                                \
-  V(Object, Object., ObjectConstructor, 2030609793)                            \
-  V(Object, get:_cid, ObjectCid, 732498573)                                    \
-  V(_ObjectArray, get:length, ObjectArrayLength, 405297088)                    \
-  V(_ImmutableArray, get:length, ImmutableArrayLength, 433698233)              \
-  V(_TypedList, get:length, TypedDataLength, 1004567191)                       \
-  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 1219036864)                    \
-  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1219036864)                  \
-  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 1219036864)                  \
-  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1219036864)                \
-  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 1219036864)                  \
-  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 1219036864)                \
-  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 1465214182)              \
-  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1465214182)              \
-  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 2133963445)          \
-  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 1865947547)                    \
-  V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 1865947547)                  \
-  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 1865947547)                  \
-  V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 1865947547)                \
-  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1865947547)                  \
-  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1865947547)                \
-  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 2034634179)              \
-  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 2034634179)              \
-  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 773019010)           \
-  V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050)          \
-  V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 725548050)     \
-  V(_GrowableObjectArray, _setData, GrowableArraySetData, 588108129)           \
-  V(_GrowableObjectArray, _setLength, GrowableArraySetLength, 279007375)       \
-  V(_StringBase, get:length, StringBaseLength, 320803993)                      \
-  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 110631520)                    \
-  V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 1574843871)                 \
-  V(_StringBase, [], StringBaseCharAt, 2105190389)                             \
-  V(_OneByteString, _setAt, OneByteStringSetAt, 1038132016)                    \
-  V(_IntegerImplementation, toDouble, IntegerToDouble, 1331752138)             \
-  V(_Double, toInt, DoubleToInteger, 630286253)                                \
-  V(_Double, truncateToDouble, DoubleTruncate, 1804056693)                     \
-  V(_Double, roundToDouble, DoubleRound, 1804056693)                           \
-  V(_Double, floorToDouble, DoubleFloor, 1804056693)                           \
-  V(_Double, ceilToDouble, DoubleCeil, 1804056693)                             \
-  V(_Double, pow, DoublePow, 102305574)                                        \
-  V(_Double, _modulo, DoubleMod, 663439671)                                    \
-  V(::, sqrt, MathSqrt, 1662640002)                                            \
-  V(::, sin, MathSin, 1273932041)                                              \
-  V(::, cos, MathCos, 1749547468)                                              \
-  V(::, min, MathMin, 269896129)                                               \
-  V(::, max, MathMax, 1286442186)                                              \
-  V(Float32x4, Float32x4., Float32x4Constructor, 1492157358)                   \
-  V(Float32x4, Float32x4.zero, Float32x4Zero, 444339161)                       \
-  V(Float32x4, Float32x4.splat, Float32x4Splat, 1843231403)                    \
-  V(_Float32x4, _shuffle, Float32x4Shuffle, 1618450134)                        \
-  V(_Float32x4, get:x, Float32x4ShuffleX, 211144022)                           \
-  V(_Float32x4, get:y, Float32x4ShuffleY, 211144022)                           \
-  V(_Float32x4, get:z, Float32x4ShuffleZ, 211144022)                           \
-  V(_Float32x4, get:w, Float32x4ShuffleW, 211144022)                           \
-  V(_Float32x4, _cmpequal, Float32x4Equal, 2103153736)                         \
-  V(_Float32x4, _cmpgt, Float32x4GreaterThan, 2103153736)                      \
-  V(_Float32x4, _cmpgte, Float32x4GreaterThanOrEqual, 2103153736)              \
-  V(_Float32x4, _cmplt, Float32x4LessThan, 2103153736)                         \
-  V(_Float32x4, _cmplte, Float32x4LessThanOrEqual, 2103153736)                 \
-  V(_Float32x4, _cmpnequal, Float32x4NotEqual, 2103153736)                     \
-  V(_Float32x4, _min, Float32x4Min, 465519415)                                 \
-  V(_Float32x4, _max, Float32x4Max, 465519415)                                 \
-  V(_Float32x4, _scale, Float32x4Scale, 42272341)                              \
-  V(_Float32x4, _sqrt, Float32x4Sqrt, 157194268)                               \
-  V(_Float32x4, _reciprocalSqrt, Float32x4ReciprocalSqrt, 157194268)           \
-  V(_Float32x4, _reciprocal, Float32x4Reciprocal, 157194268)                   \
-  V(_Float32x4, _negate, Float32x4Negate, 157194268)                           \
-  V(_Float32x4, _abs, Float32x4Absolute, 157194268)                            \
-  V(_Float32x4, _clamp, Float32x4Clamp, 1553901850)                            \
-  V(_Float32x4, withX, Float32x4WithX, 1816943014)                             \
-  V(_Float32x4, withY, Float32x4WithY, 820404963)                              \
-  V(_Float32x4, withZ, Float32x4WithZ, 881355277)                              \
-  V(_Float32x4, withW, Float32x4WithW, 441497035)                              \
-  V(_Float32x4, _toUint32x4, Float32x4ToUint32x4, 802289205)                   \
-  V(_Float32x4, withZWInXY, Float32x4WithZWInXY, 465519415)                    \
-  V(_Float32x4, interleaveXY, Float32x4InterleaveXY, 465519415)                \
-  V(_Float32x4, interleaveZW, Float32x4InterleaveZW, 465519415)                \
-  V(_Float32x4, interleaveXYPairs, Float32x4InterleaveXYPairs, 465519415)      \
-  V(_Float32x4, interleaveZWPairs, Float32x4InterleaveZWPairs, 465519415)      \
-  V(Uint32x4, Uint32x4.bool, Uint32x4BoolConstructor, 487876159)               \
-  V(_Uint32x4, get:flagX, Uint32x4GetFlagX, 782547529)                         \
-  V(_Uint32x4, get:flagY, Uint32x4GetFlagY, 782547529)                         \
-  V(_Uint32x4, get:flagZ, Uint32x4GetFlagZ, 782547529)                         \
-  V(_Uint32x4, get:flagW, Uint32x4GetFlagW, 782547529)                         \
-  V(_Uint32x4, select, Uint32x4Select, 810336099)                              \
-  V(_Uint32x4, withFlagX, Uint32x4WithFlagX, 25547408)                         \
-  V(_Uint32x4, withFlagY, Uint32x4WithFlagY, 1176493005)                       \
-  V(_Uint32x4, withFlagZ, Uint32x4WithFlagZ, 1237443319)                       \
-  V(_Uint32x4, withFlagW, Uint32x4WithFlagW, 797585077)                        \
-  V(_Uint32x4, _toFloat32x4, Uint32x4ToUint32x4, 912844231)                    \
+  V(::, identical, ObjectIdentical, 101186973)                                 \
+  V(Object, Object., ObjectConstructor, 1058525712)                            \
+  V(Object, get:_cid, ObjectCid, 2099568593)                                   \
+  V(_ObjectArray, get:length, ObjectArrayLength, 1441000484)                   \
+  V(_ImmutableArray, get:length, ImmutableArrayLength, 1430953867)             \
+  V(_TypedList, get:length, TypedDataLength, 117589485)                        \
+  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 788387678)                     \
+  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1137892349)                  \
+  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 464167270)                   \
+  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 673378812)                 \
+  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 1230275232)                  \
+  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 976951843)                 \
+  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 215932309)               \
+  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 450032954)               \
+  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1602836552)          \
+  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 250049637)                     \
+  V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 1792593311)                  \
+  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 1958159284)                  \
+  V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 1244907090)                \
+  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1058956549)                  \
+  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1054500835)                \
+  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 1426038329)              \
+  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 1289924817)              \
+  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 370513644)           \
+  V(_GrowableObjectArray, get:length, GrowableArrayLength, 767561362)          \
+  V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 874559046)     \
+  V(_GrowableObjectArray, _setData, GrowableArraySetData, 1302055339)          \
+  V(_GrowableObjectArray, _setLength, GrowableArraySetLength, 1016226171)      \
+  V(_StringBase, get:length, StringBaseLength, 1158042795)                     \
+  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 1588094430)                   \
+  V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 1452213966)                 \
+  V(_StringBase, [], StringBaseCharAt, 924930519)                              \
+  V(_OneByteString, _setAt, OneByteStringSetAt, 456985263)                     \
+  V(_IntegerImplementation, toDouble, IntegerToDouble, 2141284842)             \
+  V(_IntegerImplementation, _leftShiftWithMask32, IntegerLeftShiftWithMask32,  \
+      964472615)                                                               \
+  V(_Double, toInt, DoubleToInteger, 1580473283)                               \
+  V(_Double, truncateToDouble, DoubleTruncate, 849350203)                      \
+  V(_Double, roundToDouble, DoubleRound, 500368418)                            \
+  V(_Double, floorToDouble, DoubleFloor, 763548522)                            \
+  V(_Double, ceilToDouble, DoubleCeil, 976697019)                              \
+  V(_Double, pow, DoublePow, 1240251670)                                       \
+  V(_Double, _modulo, DoubleMod, 1850917533)                                   \
+  V(::, sqrt, MathSqrt, 465520247)                                             \
+  V(::, sin, MathSin, 730107143)                                               \
+  V(::, cos, MathCos, 1282146521)                                              \
+  V(::, min, MathMin, 1584022354)                                              \
+  V(::, max, MathMax, 328632232)                                               \
+  V(Float32x4, Float32x4., Float32x4Constructor, 1876089990)                   \
+  V(Float32x4, Float32x4.zero, Float32x4Zero, 1903586222)                      \
+  V(Float32x4, Float32x4.splat, Float32x4Splat, 38462589)                      \
+  V(_Float32x4, _shuffle, Float32x4Shuffle, 2044955136)                        \
+  V(_Float32x4, get:x, Float32x4ShuffleX, 1019523296)                          \
+  V(_Float32x4, get:y, Float32x4ShuffleY, 710282243)                           \
+  V(_Float32x4, get:z, Float32x4ShuffleZ, 1612806041)                          \
+  V(_Float32x4, get:w, Float32x4ShuffleW, 1113701403)                          \
+  V(_Float32x4, _cmpequal, Float32x4Equal, 1559121703)                         \
+  V(_Float32x4, _cmpgt, Float32x4GreaterThan, 1959692892)                      \
+  V(_Float32x4, _cmpgte, Float32x4GreaterThanOrEqual, 2128251808)              \
+  V(_Float32x4, _cmplt, Float32x4LessThan, 405464198)                          \
+  V(_Float32x4, _cmplte, Float32x4LessThanOrEqual, 1217836152)                 \
+  V(_Float32x4, _cmpnequal, Float32x4NotEqual, 498820440)                      \
+  V(_Float32x4, _min, Float32x4Min, 1354880316)                                \
+  V(_Float32x4, _max, Float32x4Max, 171574145)                                 \
+  V(_Float32x4, _scale, Float32x4Scale, 1553559438)                            \
+  V(_Float32x4, _sqrt, Float32x4Sqrt, 612006112)                               \
+  V(_Float32x4, _reciprocalSqrt, Float32x4ReciprocalSqrt, 606139302)           \
+  V(_Float32x4, _reciprocal, Float32x4Reciprocal, 606284658)                   \
+  V(_Float32x4, _negate, Float32x4Negate, 1391098465)                          \
+  V(_Float32x4, _abs, Float32x4Absolute, 1255666131)                           \
+  V(_Float32x4, _clamp, Float32x4Clamp, 736513790)                             \
+  V(_Float32x4, withX, Float32x4WithX, 1812990172)                             \
+  V(_Float32x4, withY, Float32x4WithY, 870795583)                              \
+  V(_Float32x4, withZ, Float32x4WithZ, 784227740)                              \
+  V(_Float32x4, withW, Float32x4WithW, 868173303)                              \
+  V(_Float32x4, _toUint32x4, Float32x4ToUint32x4, 147627074)                   \
+  V(_Float32x4, withZWInXY, Float32x4WithZWInXY, 1850941421)                   \
+  V(_Float32x4, interleaveXY, Float32x4InterleaveXY, 1789523505)               \
+  V(_Float32x4, interleaveZW, Float32x4InterleaveZW, 1137302773)               \
+  V(_Float32x4, interleaveXYPairs, Float32x4InterleaveXYPairs, 2138669236)     \
+  V(_Float32x4, interleaveZWPairs, Float32x4InterleaveZWPairs, 1541966446)     \
+  V(Uint32x4, Uint32x4.bool, Uint32x4BoolConstructor, 733327933)               \
+  V(_Uint32x4, get:flagX, Uint32x4GetFlagX, 765894409)                         \
+  V(_Uint32x4, get:flagY, Uint32x4GetFlagY, 1226233321)                        \
+  V(_Uint32x4, get:flagZ, Uint32x4GetFlagZ, 1455452476)                        \
+  V(_Uint32x4, get:flagW, Uint32x4GetFlagW, 1608549245)                        \
+  V(_Uint32x4, select, Uint32x4Select, 881590808)                              \
+  V(_Uint32x4, withFlagX, Uint32x4WithFlagX, 1987921054)                       \
+  V(_Uint32x4, withFlagY, Uint32x4WithFlagY, 831632614)                        \
+  V(_Uint32x4, withFlagZ, Uint32x4WithFlagZ, 465765612)                        \
+  V(_Uint32x4, withFlagW, Uint32x4WithFlagW, 1545009993)                       \
+  V(_Uint32x4, _toFloat32x4, Uint32x4ToUint32x4, 1545735523)                   \
 
 
 // A list of core function that should always be inlined.
 #define INLINE_WHITE_LIST(V)                                                   \
-  V(ListIterator, moveNext, ListIteratorMoveNext, 203118278)                   \
-  V(_GrowableObjectArray, get:iterator, GrowableArrayIterator, 810824939)      \
-  V(_GrowableObjectArray, forEach, GrowableArrayForEach, 619038738)
+  V(ListIterator, moveNext, ListIteratorMoveNext, 657540761)                   \
+  V(_GrowableObjectArray, get:iterator, GrowableArrayIterator, 281980741)      \
+  V(_GrowableObjectArray, forEach, GrowableArrayForEach, 334448248)
 
 
 // Class that recognizes the name and owner of a function and returns the
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index fd16073..3f22ad0 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -16,117 +16,117 @@
 // When adding a new function for intrinsification add a 0 as fingerprint,
 // build and run to get the correct fingerprint from the mismatch error.
 #define CORE_LIB_INTRINSIC_LIST(V)                                             \
-  V(_Smi, ~, Smi_bitNegate, 2098673794)                                        \
-  V(_Double, >, Double_greaterThan, 498448864)                                 \
-  V(_Double, >=, Double_greaterEqualThan, 1322959863)                          \
-  V(_Double, <, Double_lessThan, 1595326820)                                   \
-  V(_Double, <=, Double_lessEqualThan, 1322930072)                             \
-  V(_Double, ==, Double_equal, 1012968674)                                     \
-  V(_Double, +, Double_add, 407090160)                                         \
-  V(_Double, -, Double_sub, 1801868246)                                        \
-  V(_Double, *, Double_mul, 984784342)                                         \
-  V(_Double, /, Double_div, 1399344917)                                        \
-  V(_Double, get:isNaN, Double_getIsNaN, 54462366)                             \
-  V(_Double, get:isNegative, Double_getIsNegative, 54462366)                   \
-  V(_Double, _mulFromInteger, Double_mulFromInteger, 550294258)                \
-  V(_Double, .fromInteger, Double_fromInteger, 881555713)                      \
-  V(_ObjectArray, ., ObjectArray_Allocate, 1149848530)                         \
-  V(_ObjectArray, get:length, Array_getLength, 405297088)                      \
-  V(_ObjectArray, [], Array_getIndexed, 1573881683)                            \
-  V(_ObjectArray, []=, Array_setIndexed, 1644545484)                           \
-  V(_GrowableObjectArray, .withData, GrowableArray_Allocate, 569069682)        \
-  V(_GrowableObjectArray, get:length, GrowableArray_getLength, 725548050)      \
-  V(_GrowableObjectArray, get:_capacity, GrowableArray_getCapacity, 725548050) \
-  V(_GrowableObjectArray, [], GrowableArray_getIndexed, 1889032295)            \
-  V(_GrowableObjectArray, []=, GrowableArray_setIndexed, 934874427)            \
-  V(_GrowableObjectArray, _setLength, GrowableArray_setLength, 279007375)      \
-  V(_GrowableObjectArray, _setData, GrowableArray_setData, 588108129)          \
-  V(_GrowableObjectArray, add, GrowableArray_add, 112207566)                   \
-  V(_ImmutableArray, [], ImmutableArray_getIndexed, 1456194617)                \
-  V(_ImmutableArray, get:length, ImmutableArray_getLength, 433698233)          \
-  V(Object, ==, Object_equal, 2126867222)                                      \
-  V(_StringBase, get:hashCode, String_getHashCode, 320803993)                  \
-  V(_StringBase, get:isEmpty, String_getIsEmpty, 110631520)                    \
-  V(_StringBase, get:length, String_getLength, 320803993)                      \
-  V(_StringBase, codeUnitAt, String_codeUnitAt, 1574843871)                    \
-  V(_OneByteString, get:hashCode, OneByteString_getHashCode, 682660413)        \
+  V(_Smi, ~, Smi_bitNegate, 824551298)                                         \
+  V(_Double, >, Double_greaterThan, 1021232334)                                \
+  V(_Double, >=, Double_greaterEqualThan, 324955595)                           \
+  V(_Double, <, Double_lessThan, 978151157)                                    \
+  V(_Double, <=, Double_lessEqualThan, 1169397675)                             \
+  V(_Double, ==, Double_equal, 223604237)                                      \
+  V(_Double, +, Double_add, 295873577)                                         \
+  V(_Double, -, Double_sub, 1180117486)                                        \
+  V(_Double, *, Double_mul, 1999983053)                                        \
+  V(_Double, /, Double_div, 1904009451)                                        \
+  V(_Double, get:isNaN, Double_getIsNaN, 266197199)                            \
+  V(_Double, get:isNegative, Double_getIsNegative, 264643149)                  \
+  V(_Double, _mulFromInteger, Double_mulFromInteger, 930284178)                \
+  V(_Double, .fromInteger, Double_fromInteger, 1488487599)                     \
+  V(_ObjectArray, ., ObjectArray_Allocate, 712468799)                          \
+  V(_ObjectArray, get:length, Array_getLength, 1441000484)                     \
+  V(_ObjectArray, [], Array_getIndexed, 658292540)                             \
+  V(_ObjectArray, []=, Array_setIndexed, 134661366)                            \
+  V(_GrowableObjectArray, .withData, GrowableArray_Allocate, 917195627)        \
+  V(_GrowableObjectArray, get:length, GrowableArray_getLength, 767561362)      \
+  V(_GrowableObjectArray, get:_capacity, GrowableArray_getCapacity, 874559046) \
+  V(_GrowableObjectArray, [], GrowableArray_getIndexed, 1020883940)            \
+  V(_GrowableObjectArray, []=, GrowableArray_setIndexed, 366077215)            \
+  V(_GrowableObjectArray, _setLength, GrowableArray_setLength, 1016226171)     \
+  V(_GrowableObjectArray, _setData, GrowableArray_setData, 1302055339)         \
+  V(_GrowableObjectArray, add, GrowableArray_add, 1442410650)                  \
+  V(_ImmutableArray, [], ImmutableArray_getIndexed, 1483706518)                \
+  V(_ImmutableArray, get:length, ImmutableArray_getLength, 1430953867)         \
+  V(Object, ==, Object_equal, 677817295)                                       \
+  V(_StringBase, get:hashCode, String_getHashCode, 1654013013)                 \
+  V(_StringBase, get:isEmpty, String_getIsEmpty, 1588094430)                   \
+  V(_StringBase, get:length, String_getLength, 1158042795)                     \
+  V(_StringBase, codeUnitAt, String_codeUnitAt, 1452213966)                    \
+  V(_OneByteString, get:hashCode, OneByteString_getHashCode, 1350708273)       \
   V(_OneByteString, _substringUncheckedNative,                                 \
-      OneByteString_substringUnchecked, 756784624)                             \
-  V(_OneByteString, _setAt, OneByteString_setAt, 1038132016)                   \
-  V(_OneByteString, _allocate, OneByteString_allocate, 716379334)              \
+      OneByteString_substringUnchecked, 1409543330)                            \
+  V(_OneByteString, _setAt, OneByteString_setAt, 456985263)                    \
+  V(_OneByteString, _allocate, OneByteString_allocate, 1842287414)             \
 
 
 #define CORE_INTEGER_LIB_INTRINSIC_LIST(V)                                     \
   V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger,           \
-    1074291215)                                                                \
-  V(_IntegerImplementation, +, Integer_add, 25837296)                          \
+    1061271878)                                                                \
+  V(_IntegerImplementation, +, Integer_add, 714540399)                         \
   V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger,           \
-    1074291215)                                                                \
-  V(_IntegerImplementation, -, Integer_sub, 1697139934)                        \
+    585090868)                                                                 \
+  V(_IntegerImplementation, -, Integer_sub, 1880284412)                        \
   V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger,           \
-    1074291215)                                                                \
-  V(_IntegerImplementation, *, Integer_mul, 110370751)                         \
-  V(_IntegerImplementation, %, Integer_modulo, 980686435)                      \
-  V(_IntegerImplementation, remainder, Integer_remainder, 1536426035)          \
-  V(_IntegerImplementation, ~/, Integer_truncDivide, 2059401166)               \
-  V(_IntegerImplementation, unary-, Integer_negate, 675709702)                 \
+    1145805333)                                                                \
+  V(_IntegerImplementation, *, Integer_mul, 1935440252)                        \
+  V(_IntegerImplementation, %, Integer_modulo, 1121942909)                     \
+  V(_IntegerImplementation, remainder, Integer_remainder, 2140653009)          \
+  V(_IntegerImplementation, ~/, Integer_truncDivide, 250357385)                \
+  V(_IntegerImplementation, unary-, Integer_negate, 732448114)                 \
   V(_IntegerImplementation, _bitAndFromInteger,                                \
-    Integer_bitAndFromInteger, 1074291215)                                     \
-  V(_IntegerImplementation, &, Integer_bitAnd, 759019505)                      \
+    Integer_bitAndFromInteger, 1957162220)                                     \
+  V(_IntegerImplementation, &, Integer_bitAnd, 1677634910)                     \
   V(_IntegerImplementation, _bitOrFromInteger,                                 \
-    Integer_bitOrFromInteger, 1074291215)                                      \
-  V(_IntegerImplementation, |, Integer_bitOr, 1280367298)                      \
+    Integer_bitOrFromInteger, 331026365)                                       \
+  V(_IntegerImplementation, |, Integer_bitOr, 1062616305)                      \
   V(_IntegerImplementation, _bitXorFromInteger,                                \
-    Integer_bitXorFromInteger, 1074291215)                                     \
-  V(_IntegerImplementation, ^, Integer_bitXor, 686827811)                      \
+    Integer_bitXorFromInteger, 1884970526)                                     \
+  V(_IntegerImplementation, ^, Integer_bitXor, 2111001841)                     \
   V(_IntegerImplementation,                                                    \
     _greaterThanFromInteger,                                                   \
-    Integer_greaterThanFromInt, 2056270230)                                    \
-  V(_IntegerImplementation, >, Integer_greaterThan, 866987265)                 \
-  V(_IntegerImplementation, ==, Integer_equal, 1763184121)                     \
+    Integer_greaterThanFromInt, 1634594614)                                    \
+  V(_IntegerImplementation, >, Integer_greaterThan, 195542579)                 \
+  V(_IntegerImplementation, ==, Integer_equal, 288044426)                      \
   V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger,           \
-    2056270230)                                                                \
-  V(_IntegerImplementation, <, Integer_lessThan, 1423913958)                   \
-  V(_IntegerImplementation, <=, Integer_lessEqualThan, 1087447066)             \
-  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 1087476857)          \
-  V(_IntegerImplementation, <<, Integer_shl, 1600590181)                       \
-  V(_IntegerImplementation, >>, Integer_sar, 237416447)                        \
-  V(_Double, toInt, Double_toInt, 630286253)
+    45967303)                                                                  \
+  V(_IntegerImplementation, <, Integer_lessThan, 1133694259)                   \
+  V(_IntegerImplementation, <=, Integer_lessEqualThan, 1724243945)             \
+  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 879801865)           \
+  V(_IntegerImplementation, <<, Integer_shl, 1508088336)                       \
+  V(_IntegerImplementation, >>, Integer_sar, 1786839625)                       \
+  V(_Double, toInt, Double_toInt, 1580473283)
 
 
 #define MATH_LIB_INTRINSIC_LIST(V)                                             \
-  V(::, sqrt, Math_sqrt, 1662640002)                                           \
-  V(::, sin, Math_sin, 1273932041)                                             \
-  V(::, cos, Math_cos, 1749547468)                                             \
-  V(_Random, _nextState, Random_nextState, 776416255)                          \
+  V(::, sqrt, Math_sqrt, 465520247)                                            \
+  V(::, sin, Math_sin, 730107143)                                              \
+  V(::, cos, Math_cos, 1282146521)                                             \
+  V(_Random, _nextState, Random_nextState, 755413621)                          \
 
 
 #define TYPED_DATA_LIB_INTRINSIC_LIST(V)                                       \
-  V(_TypedList, get:length, TypedData_getLength, 1004567191)                   \
-  V(_Int8Array, _new, TypedData_Int8Array_new, 1708300323)                     \
-  V(_Uint8Array, _new, TypedData_Uint8Array_new, 280387497)                    \
-  V(_Uint8ClampedArray, _new, TypedData_Uint8ClampedArray_new, 1035267417)     \
-  V(_Int16Array, _new, TypedData_Int16Array_new, 1460383283)                   \
-  V(_Uint16Array, _new, TypedData_Uint16Array_new, 737997883)                  \
-  V(_Int32Array, _new, TypedData_Int32Array_new, 1608749233)                   \
-  V(_Uint32Array, _new, TypedData_Uint32Array_new, 1955293459)                 \
-  V(_Int64Array, _new, TypedData_Int64Array_new, 1992227270)                   \
-  V(_Uint64Array, _new, TypedData_Uint64Array_new, 291118076)                  \
-  V(_Float32Array, _new, TypedData_Float32Array_new, 962527805)                \
-  V(_Float64Array, _new, TypedData_Float64Array_new, 1871142667)               \
-  V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 1873359556)           \
-  V(_Int8Array, ., TypedData_Int8Array_factory, 1139775342)                    \
-  V(_Uint8Array, ., TypedData_Uint8Array_factory, 2065936658)                  \
-  V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1420655937)    \
-  V(_Int16Array, ., TypedData_Int16Array_factory, 1401847016)                  \
-  V(_Uint16Array, ., TypedData_Uint16Array_factory, 967612741)                 \
-  V(_Int32Array, ., TypedData_Int32Array_factory, 332168564)                   \
-  V(_Uint32Array, ., TypedData_Uint32Array_factory, 966424258)                 \
-  V(_Int64Array, ., TypedData_Int64Array_factory, 541618991)                   \
-  V(_Uint64Array, ., TypedData_Uint64Array_factory, 1085703705)                \
-  V(_Float32Array, ., TypedData_Float32Array_factory, 1691006880)              \
-  V(_Float64Array, ., TypedData_Float64Array_factory, 1867705160)              \
-  V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1739837241)          \
+  V(_TypedList, get:length, TypedData_getLength, 117589485)                    \
+  V(_Int8Array, _new, TypedData_Int8Array_new, 1133705629)                     \
+  V(_Uint8Array, _new, TypedData_Uint8Array_new, 1643490889)                   \
+  V(_Uint8ClampedArray, _new, TypedData_Uint8ClampedArray_new, 1212601488)     \
+  V(_Int16Array, _new, TypedData_Int16Array_new, 1241260890)                   \
+  V(_Uint16Array, _new, TypedData_Uint16Array_new, 337798210)                  \
+  V(_Int32Array, _new, TypedData_Int32Array_new, 845463081)                    \
+  V(_Uint32Array, _new, TypedData_Uint32Array_new, 1406929599)                 \
+  V(_Int64Array, _new, TypedData_Int64Array_new, 408710474)                    \
+  V(_Uint64Array, _new, TypedData_Uint64Array_new, 202576356)                  \
+  V(_Float32Array, _new, TypedData_Float32Array_new, 224632748)                \
+  V(_Float64Array, _new, TypedData_Float64Array_new, 364786883)                \
+  V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 255992094)            \
+  V(_Int8Array, ., TypedData_Int8Array_factory, 1340298556)                    \
+  V(_Uint8Array, ., TypedData_Uint8Array_factory, 1775618642)                  \
+  V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 264668024)     \
+  V(_Int16Array, ., TypedData_Int16Array_factory, 1095249987)                  \
+  V(_Uint16Array, ., TypedData_Uint16Array_factory, 1275304272)                \
+  V(_Int32Array, ., TypedData_Int32Array_factory, 523449884)                   \
+  V(_Uint32Array, ., TypedData_Uint32Array_factory, 458531362)                 \
+  V(_Int64Array, ., TypedData_Int64Array_factory, 1753070829)                  \
+  V(_Uint64Array, ., TypedData_Uint64Array_factory, 1561660391)                \
+  V(_Float32Array, ., TypedData_Float32Array_factory, 368082071)               \
+  V(_Float64Array, ., TypedData_Float64Array_factory, 245916452)               \
+  V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1674296969)          \
 
 // TODO(srdjan): Implement _FixedSizeArrayIterator, get:current and
 //   _FixedSizeArrayIterator, moveNext.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index e79e89e..780f419 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -20,6 +20,7 @@
 #include "vm/object_store.h"
 #include "vm/parser.h"
 #include "vm/port.h"
+#include "vm/reusable_handles.h"
 #include "vm/service.h"
 #include "vm/simulator.h"
 #include "vm/stack_frame.h"
@@ -720,16 +721,12 @@
   for (int i = 0; i < libraries.Length(); i++) {
     library ^= libraries.At(i);
     Class& cls = Class::Handle();
-    ClassDictionaryIterator iter(library);
+    ClassDictionaryIterator iter(library,
+                                 ClassDictionaryIterator::kIteratePrivate);
     while (iter.HasNext()) {
       cls = iter.GetNextClass();
       AddFunctionsFromClass(cls, &invoked_functions);
     }
-    Array& anon_classes = Array::Handle(library.raw_ptr()->anonymous_classes_);
-    for (int i = 0; i < library.raw_ptr()->num_anonymous_; i++) {
-      cls ^= anon_classes.At(i);
-      AddFunctionsFromClass(cls, &invoked_functions);
-    }
   }
   invoked_functions.Sort(MostUsedFunctionFirst);
   for (int i = 0; i < invoked_functions.length(); i++) {
@@ -1105,16 +1102,6 @@
 }
 
 
-void ReusableHandleScope::ResetHandles() {
-#define CLEAR_REUSABLE_HANDLE(object)                                          \
-  if (!object##Handle().IsNull()) {                                            \
-    object##Handle().raw_ = Object::null();                                    \
-  }
-
-  REUSABLE_HANDLE_LIST(CLEAR_REUSABLE_HANDLE);
-}
-
-
 static char* GetRootScriptUri(Isolate* isolate) {
   const Library& library =
       Library::Handle(isolate->object_store()->root_library());
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 2fc17d1..7a71eb4 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -707,83 +707,10 @@
   static Dart_IsolateInterruptCallback vmstats_callback_;
 
   friend class ReusableHandleScope;
+  friend class ReusableObjectHandleScope;
   DISALLOW_COPY_AND_ASSIGN(Isolate);
 };
 
-// The class ReusableHandleScope is used in regions of the
-// virtual machine where isolate specific reusable handles are used.
-// This class asserts that we do not add code that will result in recursive
-// uses of reusable handles.
-// It is used as follows:
-// {
-//   ReusableHandleScope reused_handles(isolate);
-//   ....
-//   .....
-//   code that uses isolate specific reusable handles.
-//   Array& funcs = reused_handles.ArrayHandle();
-//   ....
-// }
-#if defined(DEBUG)
-class ReusableHandleScope : public StackResource {
- public:
-  explicit ReusableHandleScope(Isolate* isolate)
-      : StackResource(isolate), isolate_(isolate) {
-    ASSERT(!isolate->reusable_handle_scope_active());
-    isolate->set_reusable_handle_scope_active(true);
-  }
-  ReusableHandleScope()
-      : StackResource(Isolate::Current()), isolate_(Isolate::Current()) {
-    ASSERT(!isolate()->reusable_handle_scope_active());
-    isolate()->set_reusable_handle_scope_active(true);
-  }
-  ~ReusableHandleScope() {
-    ASSERT(isolate()->reusable_handle_scope_active());
-    isolate()->set_reusable_handle_scope_active(false);
-    ResetHandles();
-  }
-
-#define REUSABLE_HANDLE_ACCESSORS(object)                                      \
-  object& object##Handle() {                                                   \
-    ASSERT(isolate_->object##_handle_ != NULL);                                \
-    return *isolate_->object##_handle_;                                        \
-  }                                                                            \
-
-  REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ACCESSORS)
-#undef REUSABLE_HANDLE_ACCESSORS
-
- private:
-  void ResetHandles();
-  Isolate* isolate_;
-  DISALLOW_COPY_AND_ASSIGN(ReusableHandleScope);
-};
-#else
-class ReusableHandleScope : public ValueObject {
- public:
-  explicit ReusableHandleScope(Isolate* isolate) : isolate_(isolate) {
-  }
-  ReusableHandleScope() : isolate_(Isolate::Current()) {
-  }
-  ~ReusableHandleScope() {
-    ResetHandles();
-  }
-
-#define REUSABLE_HANDLE_ACCESSORS(object)                                      \
-  object& object##Handle() {                                                   \
-    ASSERT(isolate_->object##_handle_ != NULL);                                \
-    return *isolate_->object##_handle_;                                        \
-  }                                                                            \
-
-  REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ACCESSORS)
-#undef REUSABLE_HANDLE_ACCESSORS
-
- private:
-  void ResetHandles();
-  Isolate* isolate_;
-  DISALLOW_COPY_AND_ASSIGN(ReusableHandleScope);
-};
-#endif  // defined(DEBUG)
-
-
 
 // When we need to execute code in an isolate, we use the
 // StartIsolateScope.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index a6d7364..b92355e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -34,6 +34,7 @@
 #include "vm/object_id_ring.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
+#include "vm/reusable_handles.h"
 #include "vm/runtime_entry.h"
 #include "vm/scopes.h"
 #include "vm/stack_frame.h"
@@ -58,6 +59,7 @@
 DECLARE_FLAG(bool, trace_compiler);
 DECLARE_FLAG(bool, eliminate_type_checks);
 DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, error_on_bad_override);
 
 static const char* kGetterPrefix = "get:";
 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
@@ -94,6 +96,8 @@
 RawClass* Object::class_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::dynamic_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::void_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+RawType* Object::dynamic_type_ = reinterpret_cast<RawType*>(RAW_NULL);
+RawType* Object::void_type_ = reinterpret_cast<RawType*>(RAW_NULL);
 RawClass* Object::unresolved_class_class_ =
     reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::type_arguments_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
@@ -439,21 +443,10 @@
         Object::Allocate(kNullCid, Instance::InstanceSize(), Heap::kOld);
   }
 
-  cls = Class::New<Instance>(kDynamicCid);
-  cls.set_is_finalized();
-  cls.set_is_type_finalized();
-  cls.set_is_abstract();
-  dynamic_class_ = cls.raw();
-
   // Allocate the remaining VM internal classes.
   cls = Class::New<UnresolvedClass>();
   unresolved_class_class_ = cls.raw();
 
-  cls = Class::New<Instance>(kVoidCid);
-  cls.set_is_finalized();
-  cls.set_is_type_finalized();
-  void_class_ = cls.raw();
-
   cls = Class::New<TypeArguments>();
   type_arguments_class_ = cls.raw();
 
@@ -566,6 +559,28 @@
     empty_array_->raw()->ptr()->length_ = Smi::New(0);
   }
 
+  cls = Class::New<Instance>(kDynamicCid);
+  cls.set_is_finalized();
+  cls.set_is_type_finalized();
+  cls.set_is_abstract();
+  dynamic_class_ = cls.raw();
+
+  cls = Class::New<Instance>(kVoidCid);
+  cls.set_is_finalized();
+  cls.set_is_type_finalized();
+  void_class_ = cls.raw();
+
+  cls = Class::New<Type>();
+  cls.set_is_finalized();
+  cls.set_is_type_finalized();
+  isolate->object_store()->set_type_class(cls);
+
+  cls = dynamic_class_;
+  dynamic_type_ = Type::NewNonParameterizedType(cls);
+
+  cls = void_class_;
+  void_type_ = Type::NewNonParameterizedType(cls);
+
   // Allocate and initialize singleton true and false boolean objects.
   cls = Class::New<Bool>();
   isolate->object_store()->set_bool_class(cls);
@@ -840,6 +855,8 @@
   RegisterClass(cls, Symbols::Bool(), core_lib);
   pending_classes.Add(cls, Heap::kOld);
 
+  // TODO(12364): The class 'Null' is not registered in the class dictionary
+  // because it is not exported by dart:core.
   cls = Class::New<Instance>(kNullCid);
   cls.set_name(Symbols::Null());
   // We immediately mark Null as finalized because it has no corresponding
@@ -962,6 +979,14 @@
   RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
   pending_classes.Add(cls, Heap::kOld);
 
+  // Abstract super class for all signature classes.
+  cls = Class::New<Instance>(kIllegalCid);
+  cls.set_is_prefinalized();
+  RegisterPrivateClass(cls, Symbols::FunctionImpl(), core_lib);
+  pending_classes.Add(cls, Heap::kOld);
+  type = Type::NewNonParameterizedType(cls);
+  object_store->set_function_impl_type(type);
+
   cls = Class::New<WeakProperty>();
   object_store->set_weak_property_class(cls);
   RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib);
@@ -1063,9 +1088,9 @@
   type = object_store->object_type();
   cls.set_super_type(type);
 
-  // Note: The abstract class Function is represented by VM class
-  // DartFunction, not VM class Function.
-  cls = Class::New<DartFunction>();
+  // Abstract class that represents the Dart class Function.
+  cls = Class::New<Instance>(kIllegalCid);
+  cls.set_is_prefinalized();
   RegisterClass(cls, Symbols::Function(), core_lib);
   pending_classes.Add(cls, Heap::kOld);
   type = Type::NewNonParameterizedType(cls);
@@ -1093,7 +1118,6 @@
 
   name = Symbols::New("String");
   cls = Class::New<Instance>(kIllegalCid);
-  cls.set_is_prefinalized();
   RegisterClass(cls, name, core_lib);
   cls.set_is_prefinalized();
   pending_classes.Add(cls, Heap::kOld);
@@ -1112,7 +1136,6 @@
   type = Type::NewNonParameterizedType(cls);
   object_store->set_mint_type(type);
 
-  // The class 'Null' is not register in the class dictionary because it is not
   // The classes 'void' and 'dynamic' are phoney classes to make type checking
   // more regular; they live in the VM isolate. The class 'void' is not
   // registered in the class dictionary because its name is a reserved word.
@@ -1127,14 +1150,6 @@
   type = object_store->object_type();
   cls.set_super_type(type);
 
-  cls = void_class();
-  type = Type::NewNonParameterizedType(cls);
-  object_store->set_void_type(type);
-
-  cls = dynamic_class();
-  type = Type::NewNonParameterizedType(cls);
-  object_store->set_dynamic_type(type);
-
   // Finish the initialization by compiling the bootstrap scripts containing the
   // base interfaces and the implementation of the internal classes.
   const Error& error = Error::Handle(Bootstrap::LoadandCompileScripts());
@@ -1247,7 +1262,6 @@
   // Some classes are not stored in the object store. Yet we still need to
   // create their Class object so that they get put into the class_table
   // (as a side effect of Class::New()).
-  cls = Class::New<DartFunction>();
   cls = Class::New<Number>();
 
   cls = Class::New<WeakProperty>();
@@ -1874,9 +1888,9 @@
   invocation.SetNumOptionalParameters(desc.NamedCount(),
                                       false);  // Not positional.
   invocation.set_parameter_types(Array::Handle(Array::New(desc.Count(),
-                                                         Heap::kOld)));
+                                                          Heap::kOld)));
   invocation.set_parameter_names(Array::Handle(Array::New(desc.Count(),
-                                                         Heap::kOld)));
+                                                          Heap::kOld)));
   // Receiver.
   invocation.SetParameterTypeAt(0, Type::Handle(Type::DynamicType()));
   invocation.SetParameterNameAt(0, Symbols::This());
@@ -1925,17 +1939,24 @@
 }
 
 
-static const char* FormatPatchError(const char* format, const Object& obj) {
-  const char* msg = obj.ToCString();
-  intptr_t len = OS::SNPrint(NULL, 0, format, msg) + 1;
-  char* result = Isolate::Current()->current_zone()->Alloc<char>(len);
-  OS::SNPrint(result, len, format, msg);
-  return result;
+static RawError* FormatError(const Error& prev_error,
+                             const Script& script,
+                             intptr_t token_pos,
+                             const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  if (prev_error.IsNull()) {
+    return Parser::FormatError(script, token_pos, "Error", format, args);
+  } else {
+    return Parser::FormatErrorWithAppend(prev_error, script, token_pos,
+                                         "Error", format, args);
+  }
 }
 
 
 // Apply the members from the patch class to the original class.
-const char* Class::ApplyPatch(const Class& patch) const {
+bool Class::ApplyPatch(const Class& patch, Error* error) const {
+  ASSERT(error != NULL);
   ASSERT(!is_finalized());
   // Shared handles used during the iteration.
   String& member_name = String::Handle();
@@ -1975,11 +1996,14 @@
       if (orig_func.raw() != orig_implicit_ctor.raw()) {
         new_functions.Add(orig_func);
       }
-    } else if (!func.HasCompatibleParametersWith(orig_func) &&
-               !(func.IsFactory() && orig_func.IsConstructor() &&
-                 (func.num_fixed_parameters() + 1 ==
-                  orig_func.num_fixed_parameters()))) {
-      return FormatPatchError("mismatched parameters: %s", member_name);
+    } else if (func.UserVisibleSignature() !=
+               orig_func.UserVisibleSignature()) {
+      // Compare user visible signatures to ignore different implicit parameters
+      // when patching a constructor with a factory.
+      *error = FormatError(*error,  // No previous error.
+                           Script::Handle(patch.script()), func.token_pos(),
+                           "signature mismatch: '%s'", member_name.ToCString());
+      return false;
     }
   }
   for (intptr_t i = 0; i < patch_len; i++) {
@@ -2017,7 +2041,10 @@
     // Verify no duplicate additions.
     orig_field ^= LookupField(member_name);
     if (!orig_field.IsNull()) {
-      return FormatPatchError("duplicate field: %s", member_name);
+      *error = FormatError(*error,  // No previous error.
+                           Script::Handle(patch.script()), field.token_pos(),
+                           "duplicate field: %s", member_name.ToCString());
+      return false;
     }
     new_list.SetAt(i, field);
   }
@@ -2030,7 +2057,7 @@
   // The functions and fields in the patch class are no longer needed.
   patch.SetFunctions(Object::empty_array());
   patch.SetFields(Object::empty_array());
-  return NULL;
+  return true;
 }
 
 
@@ -2109,12 +2136,12 @@
                                    const Script& script,
                                    intptr_t token_pos) {
   const Class& result = Class::Handle(New(name, script, token_pos));
-  const Type& super_type = Type::Handle(Type::ObjectType());
-  ASSERT(!super_type.IsNull());
   // Instances of a signature class can only be closures.
   result.set_instance_size(Closure::InstanceSize());
   result.set_next_field_offset(Closure::InstanceSize());
-  result.set_super_type(super_type);
+  // Signature classes extend the _FunctionImpl class.
+  result.set_super_type(Type::Handle(
+      Isolate::Current()->object_store()->function_impl_type()));
   result.set_is_synthesized_class();
   result.set_type_arguments_field_offset(Closure::type_arguments_offset());
   // Implements interface "Function".
@@ -2652,10 +2679,7 @@
   ReusableHandleScope reused_handles(isolate);
   Array& funcs = reused_handles.ArrayHandle();
   funcs ^= functions();
-  if (funcs.IsNull()) {
-    // This can occur, e.g., for Null classes.
-    return Function::null();
-  }
+  ASSERT(!funcs.IsNull());
   Function& function = reused_handles.FunctionHandle();
   const intptr_t len = funcs.Length();
   if (name.IsSymbol()) {
@@ -2691,10 +2715,7 @@
   ReusableHandleScope reused_handles(isolate);
   Array& funcs = reused_handles.ArrayHandle();
   funcs ^= functions();
-  if (funcs.IsNull()) {
-    // This can occur, e.g., for Null classes.
-    return Function::null();
-  }
+  ASSERT(!funcs.IsNull());
   Function& function = reused_handles.FunctionHandle();
   String& function_name = reused_handles.StringHandle();
   intptr_t len = funcs.Length();
@@ -2795,10 +2816,7 @@
   ReusableHandleScope reused_handles(isolate);
   Array& flds = reused_handles.ArrayHandle();
   flds ^= fields();
-  if (flds.IsNull()) {
-    // This can occur, e.g., for Null classes.
-    return Field::null();
-  }
+  ASSERT(!flds.IsNull());
   Field& field = reused_handles.FieldHandle();
   String& field_name = reused_handles.StringHandle();
   intptr_t len = flds.Length();
@@ -3138,21 +3156,6 @@
 }
 
 
-static RawError* FormatError(const Error& prev_error,
-                             const Script& script,
-                             intptr_t token_pos,
-                             const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  if (prev_error.IsNull()) {
-    return Parser::FormatError(script, token_pos, "Error", format, args);
-  } else {
-    return Parser::FormatErrorWithAppend(prev_error, script, token_pos,
-                                         "Error", format, args);
-  }
-}
-
-
 bool AbstractTypeArguments::TypeTest(TypeTestKind test_kind,
                                      const AbstractTypeArguments& other,
                                      intptr_t len,
@@ -4372,24 +4375,33 @@
 }
 
 
-bool Function::HasCompatibleParametersWith(const Function& other) const {
-  const intptr_t num_fixed_params = num_fixed_parameters();
-  const intptr_t num_opt_pos_params = NumOptionalPositionalParameters();
-  const intptr_t other_num_fixed_params = other.num_fixed_parameters();
-  const intptr_t other_num_opt_pos_params =
-      other.NumOptionalPositionalParameters();
-  // A generative constructor may be compared to a redirecting factory and be
-  // compatible although it has an additional phase parameter.
-  const intptr_t num_ignored_params =
-      (other.IsRedirectingFactory() && IsConstructor()) ? 1 : 0;
-  // The default values of optional parameters can differ.
-  // This function requires the same arguments or less and accepts the same
-  // arguments or more.
-  if (((num_fixed_params - num_ignored_params) > other_num_fixed_params) ||
-      ((num_fixed_params - num_ignored_params) + num_opt_pos_params <
-       other_num_fixed_params + other_num_opt_pos_params)) {
+bool Function::HasCompatibleParametersWith(const Function& other,
+                                           Error* error) const {
+  ASSERT(FLAG_error_on_bad_override);
+  // Check that this function's signature type is a subtype of the other
+  // function's signature type.
+  if (!TypeTest(kIsSubtypeOf, Object::null_abstract_type_arguments(),
+                other, Object::null_abstract_type_arguments(), error)) {
+    // For more informative error reporting, use the location of the other
+    // function here, since the caller will use the location of this function.
+    *error = FormatError(
+        *error,  // A malformed error if non null.
+        Script::Handle(other.script()),
+        other.token_pos(),
+        "signature type '%s' of function '%s' is not a subtype of signature "
+        "type '%s' of function '%s'",
+        String::Handle(UserVisibleSignature()).ToCString(),
+        String::Handle(UserVisibleName()).ToCString(),
+        String::Handle(other.UserVisibleSignature()).ToCString(),
+        String::Handle(other.UserVisibleName()).ToCString());
     return false;
   }
+  // We should also check that if the other function explicitly specifies a
+  // default value for a formal parameter, this function does not specify a
+  // different default value for the same parameter. However, this check is not
+  // possible in the current implementation, because the default parameter
+  // values are not stored in the Function object, but discarded after a
+  // function is compiled.
   return true;
 }
 
@@ -4459,9 +4471,16 @@
       other.NumOptionalNamedParameters();
   // This function requires the same arguments or less and accepts the same
   // arguments or more.
-  if ((num_fixed_params > other_num_fixed_params) ||
-      (num_fixed_params + num_opt_pos_params <
-       other_num_fixed_params + other_num_opt_pos_params) ||
+  // A generative constructor may be compared to a redirecting factory and be
+  // compatible although it has an additional phase parameter.
+  // More generally, we can ignore implicit parameters.
+  const intptr_t num_ignored_params = NumImplicitParameters();
+  const intptr_t other_num_ignored_params = other.NumImplicitParameters();
+  if (((num_fixed_params - num_ignored_params) >
+       (other_num_fixed_params - other_num_ignored_params)) ||
+      ((num_fixed_params - num_ignored_params + num_opt_pos_params) <
+       (other_num_fixed_params - other_num_ignored_params +
+        other_num_opt_pos_params)) ||
       (num_opt_named_params < other_num_opt_named_params)) {
     return false;
   }
@@ -4494,10 +4513,11 @@
     }
   }
   // Check the types of fixed and optional positional parameters.
-  for (intptr_t i = 0;
-       i < other_num_fixed_params + other_num_opt_pos_params; i++) {
+  for (intptr_t i = 0; i < (other_num_fixed_params - other_num_ignored_params +
+                            other_num_opt_pos_params); i++) {
     if (!TestParameterType(test_kind,
-                           i, i, type_arguments, other, other_type_arguments,
+                           i + num_ignored_params, i + other_num_ignored_params,
+                           type_arguments, other, other_type_arguments,
                            malformed_error)) {
       return false;
     }
@@ -6296,7 +6316,7 @@
 
 DictionaryIterator::DictionaryIterator(const Library& library)
     : array_(Array::Handle(library.dictionary())),
-      // Last element in array is a Smi.
+      // Last element in array is a Smi indicating the number of entries used.
       size_(Array::Handle(library.dictionary()).Length() - 1),
       next_ix_(0) {
   MoveToNextObject();
@@ -6321,26 +6341,41 @@
 }
 
 
-ClassDictionaryIterator::ClassDictionaryIterator(const Library& library)
-    : DictionaryIterator(library) {
+ClassDictionaryIterator::ClassDictionaryIterator(const Library& library,
+                                                 IterationKind kind)
+    : DictionaryIterator(library),
+      anon_array_((kind == kIteratePrivate) ?
+          Array::Handle(library.anonymous_classes()) : Object::empty_array()),
+      anon_size_((kind == kIteratePrivate) ?
+                 library.num_anonymous_classes() : 0),
+      anon_ix_(0) {
   MoveToNextClass();
 }
 
 
 RawClass* ClassDictionaryIterator::GetNextClass() {
   ASSERT(HasNext());
-  int ix = next_ix_++;
-  Object& obj = Object::Handle(array_.At(ix));
-  MoveToNextClass();
-  return Class::Cast(obj).raw();
+  Class& cls = Class::Handle();
+  if (next_ix_ < size_) {
+    int ix = next_ix_++;
+    cls ^= array_.At(ix);
+    MoveToNextClass();
+    return cls.raw();
+  }
+  ASSERT(anon_ix_ < anon_size_);
+  cls ^= anon_array_.At(anon_ix_++);
+  return cls.raw();
 }
 
 
 void ClassDictionaryIterator::MoveToNextClass() {
-  Object& obj = Object::Handle(array_.At(next_ix_));
-  while (!obj.IsClass() && HasNext()) {
-    next_ix_++;
+  Object& obj = Object::Handle();
+  while (next_ix_ < size_) {
     obj = array_.At(next_ix_);
+    if (obj.IsClass()) {
+      return;
+    }
+    next_ix_++;
   }
 }
 
@@ -6727,7 +6762,7 @@
                                              intptr_t token_pos) const {
   Class& cls = Class::Handle();
   Function& func = Function::Handle();
-  ClassDictionaryIterator it(*this);
+  ClassDictionaryIterator it(*this, ClassDictionaryIterator::kIteratePrivate);
   while (it.HasNext()) {
     cls = it.GetNextClass();
     if (script.raw() == cls.script()) {
@@ -6737,19 +6772,6 @@
       }
     }
   }
-  // Look in anonymous classes for toplevel functions.
-  Array& anon_classes = Array::Handle(this->raw_ptr()->anonymous_classes_);
-  intptr_t num_anonymous = raw_ptr()->num_anonymous_;
-  for (int i = 0; i < num_anonymous; i++) {
-    cls ^= anon_classes.At(i);
-    ASSERT(!cls.IsNull());
-    if (script.raw() == cls.script()) {
-      func = cls.LookupFunctionAtToken(token_pos);
-      if (!func.IsNull()) {
-        return func.raw();
-      }
-    }
-  }
   return Function::null();
 }
 
@@ -7607,7 +7629,7 @@
   Class& cls = Class::Handle();
   for (int i = 0; i < libs.Length(); i++) {
     lib ^= libs.At(i);
-    ClassDictionaryIterator it(lib);
+    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
     while (it.HasNext()) {
       cls = it.GetNextClass();
       error = cls.EnsureIsFinalized(Isolate::Current());
@@ -7619,14 +7641,6 @@
         return error.raw();
       }
     }
-    Array& anon_classes = Array::Handle(lib.raw_ptr()->anonymous_classes_);
-    for (int i = 0; i < lib.raw_ptr()->num_anonymous_; i++) {
-      cls ^= anon_classes.At(i);
-      error = Compiler::CompileAllFunctions(cls);
-      if (!error.IsNull()) {
-        return error.raw();
-      }
-    }
   }
   return error.raw();
 }
@@ -10462,8 +10476,8 @@
 
 
 bool AbstractType::IsNullType() const {
-  return HasResolvedTypeClass() &&
-      (type_class() == Type::Handle(Type::NullType()).type_class());
+  ASSERT(Type::Handle(Type::NullType()).IsCanonical());
+  return raw() == Type::NullType();
 }
 
 
@@ -10612,12 +10626,12 @@
 
 
 RawType* Type::DynamicType() {
-  return Isolate::Current()->object_store()->dynamic_type();
+  return Object::dynamic_type();
 }
 
 
 RawType* Type::VoidType() {
-  return Isolate::Current()->object_store()->void_type();
+  return Object::void_type();
 }
 
 
@@ -11496,11 +11510,13 @@
 }
 
 
-RawInteger* Integer::New(int64_t value, Heap::Space space) {
+RawInteger* Integer::New(int64_t value, Heap::Space space, const bool silent) {
   if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) {
     return Smi::New(value);
   }
-  if (FLAG_throw_on_javascript_int_overflow && !IsJavascriptInt(value)) {
+  if (!silent &&
+      FLAG_throw_on_javascript_int_overflow &&
+      !IsJavascriptInt(value)) {
     const Integer &i = Integer::Handle(Mint::New(value));
     ThrowJavascriptIntegerOverflow(i);
   }
@@ -11743,7 +11759,9 @@
 
 
 // TODO(srdjan): Clarify handling of negative right operand in a shift op.
-RawInteger* Smi::ShiftOp(Token::Kind kind, const Smi& other) const {
+RawInteger* Smi::ShiftOp(Token::Kind kind,
+                         const Smi& other,
+                         const bool silent) const {
   intptr_t result = 0;
   const intptr_t left_value = Value();
   const intptr_t right_value = other.Value();
@@ -11762,7 +11780,7 @@
                                right_value);
           } else {
             int64_t left_64 = left_value;
-            return Integer::New(left_64 << right_value);
+            return Integer::New(left_64 << right_value, Heap::kNew, silent);
           }
         }
       }
@@ -14177,17 +14195,6 @@
 }
 
 
-const char* DartFunction::ToCString() const {
-  return "Function type class";
-}
-
-
-void DartFunction::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
-}
-
-
 intptr_t Stacktrace::Length() const {
   const Array& code_array = Array::Handle(raw_ptr()->code_array_);
   return code_array.Length();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ed73e6b..a27fae7 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -35,6 +35,7 @@
 class FinalizablePersistentHandle;
 class LocalScope;
 class ReusableHandleScope;
+class ReusableObjectHandleScope;
 class Symbols;
 
 #if defined(DEBUG)
@@ -412,6 +413,8 @@
   static RawClass* class_class() { return class_class_; }
   static RawClass* dynamic_class() { return dynamic_class_; }
   static RawClass* void_class() { return void_class_; }
+  static RawType* dynamic_type() { return dynamic_type_; }
+  static RawType* void_type() { return void_type_; }
   static RawClass* unresolved_class_class() { return unresolved_class_class_; }
   static RawClass* type_arguments_class() { return type_arguments_class_; }
   static RawClass* instantiated_type_arguments_class() {
@@ -559,6 +562,8 @@
   static RawClass* class_class_;  // Class of the Class vm object.
   static RawClass* dynamic_class_;  // Class of the 'dynamic' type.
   static RawClass* void_class_;  // Class of the 'void' type.
+  static RawType* dynamic_type_;  // Class of the 'dynamic' type.
+  static RawType* void_type_;  // Class of the 'void' type.
   static RawClass* unresolved_class_class_;  // Class of UnresolvedClass.
   // Class of the TypeArguments vm object.
   static RawClass* type_arguments_class_;
@@ -619,6 +624,7 @@
   friend class ExternalTwoByteString;
   friend class Isolate;
   friend class ReusableHandleScope;
+  friend class ReusableObjectHandleScope;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(Object);
@@ -939,7 +945,9 @@
 
   void Finalize() const;
 
-  const char* ApplyPatch(const Class& patch) const;
+  // Apply given patch class to this class.
+  // Return true on success, or false and error otherwise.
+  bool ApplyPatch(const Class& patch, Error* error) const;
 
   RawError* EnsureIsFinalized(Isolate* isolate) const;
 
@@ -1662,8 +1670,9 @@
 
   // Returns true if this function has parameters that are compatible with the
   // parameters of the other function in order for this function to override the
-  // other function. Parameter types are ignored.
-  bool HasCompatibleParametersWith(const Function& other) const;
+  // other function.
+  bool HasCompatibleParametersWith(const Function& other,
+                                   Error* malformed_error) const;
 
   // Returns true if the type of this function is a subtype of the type of
   // the other function.
@@ -2237,7 +2246,15 @@
 
 class ClassDictionaryIterator : public DictionaryIterator {
  public:
-  explicit ClassDictionaryIterator(const Library& library);
+  enum IterationKind {
+    kIteratePrivate,
+    kNoIteratePrivate
+  };
+
+  ClassDictionaryIterator(const Library& library,
+                          IterationKind kind = kNoIteratePrivate);
+
+  bool HasNext() const { return (next_ix_ < size_) || (anon_ix_ < anon_size_); }
 
   // Returns a non-null raw class.
   RawClass* GetNextClass();
@@ -2245,6 +2262,10 @@
  private:
   void MoveToNextClass();
 
+  const Array& anon_array_;
+  const int anon_size_;  // Number of anonymous classes to iterate over.
+  int anon_ix_;  // Index of next anonymous class.
+
   DISALLOW_COPY_AND_ASSIGN(ClassDictionaryIterator);
 };
 
@@ -2327,6 +2348,9 @@
   void AddLibraryMetadata(const Class& cls, intptr_t token_pos) const;
   RawObject* GetMetadata(const Object& obj) const;
 
+  intptr_t num_anonymous_classes() const { return raw_ptr()->num_anonymous_; }
+  RawArray* anonymous_classes() const { return raw_ptr()->anonymous_classes_; }
+
   // Library imports.
   void AddImport(const Namespace& ns) const;
   intptr_t num_imports() const { return raw_ptr()->num_imports_; }
@@ -4135,7 +4159,10 @@
   // Returns a canonical Integer object allocated in the old gen space.
   static RawInteger* NewCanonical(const String& str);
 
-  static RawInteger* New(int64_t value, Heap::Space space = Heap::kNew);
+  // Do not throw JavascriptIntegerOverflow if 'silent' is true.
+  static RawInteger* New(int64_t value,
+                         Heap::Space space = Heap::kNew,
+                         const bool silent = false);
 
   virtual double AsDoubleValue() const;
   virtual int64_t AsInt64Value() const;
@@ -4210,7 +4237,9 @@
     return (value >= kMinValue) && (value <= kMaxValue);
   }
 
-  RawInteger* ShiftOp(Token::Kind kind, const Smi& other) const;
+  RawInteger* ShiftOp(Token::Kind kind,
+                      const Smi& other,
+                      const bool silent = false) const;
 
   void operator=(RawSmi* value) {
     raw_ = value;
@@ -5653,15 +5682,6 @@
 };
 
 
-// DartFunction represents the abstract Dart class 'Function'.
-class DartFunction : public Instance {
- private:
-  FINAL_HEAP_OBJECT_IMPLEMENTATION(DartFunction, Instance);
-  friend class Class;
-  friend class Instance;
-};
-
-
 class Closure : public AllStatic {
  public:
   static RawFunction* function(const Instance& closure) {
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index f6602b0..e53b5d9 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -19,9 +19,8 @@
     object_type_(Type::null()),
     null_class_(Class::null()),
     null_type_(Type::null()),
-    dynamic_type_(Type::null()),
-    void_type_(Type::null()),
     function_type_(Type::null()),
+    function_impl_type_(Type::null()),
     type_class_(Class::null()),
     number_type_(Type::null()),
     int_type_(Type::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 1d51a8c..48e711a 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -61,21 +61,16 @@
     null_type_ = value.raw();
   }
 
-  RawType* dynamic_type() const { return dynamic_type_; }
-  void set_dynamic_type(const Type& value) {
-    dynamic_type_ = value.raw();
-  }
-
-  RawType* void_type() const { return void_type_; }
-  void set_void_type(const Type& value) {
-    void_type_ = value.raw();
-  }
-
   RawType* function_type() const { return function_type_; }
   void set_function_type(const Type& value) {
     function_type_ = value.raw();
   }
 
+  RawType* function_impl_type() const { return function_impl_type_; }
+  void set_function_impl_type(const Type& value) {
+    function_impl_type_ = value.raw();
+  }
+
   RawClass* type_class() const { return type_class_; }
   void set_type_class(const Class& value) { type_class_ = value.raw(); }
 
@@ -435,9 +430,8 @@
   RawType* object_type_;
   RawClass* null_class_;
   RawType* null_type_;
-  RawType* dynamic_type_;
-  RawType* void_type_;
   RawType* function_type_;
+  RawType* function_impl_type_;
   RawClass* type_class_;
   RawClass* type_parameter_class_;
   RawClass* bounded_type_class_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 25e7fcb..e4145c6 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -31,8 +31,25 @@
   const Script& script = Script::Handle();
   const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
 
-  // Class has no fields.
-  cls.SetFields(Object::empty_array());
+  // Class has no fields and no functions yet.
+  EXPECT_EQ(Array::Handle(cls.fields()).Length(), 0);
+  EXPECT_EQ(Array::Handle(cls.functions()).Length(), 0);
+
+  // Setup the interfaces in the class.
+  const Array& interfaces = Array::Handle(Array::New(2));
+  Class& interface = Class::Handle();
+  String& interface_name = String::Handle();
+  interface_name = Symbols::New("Harley");
+  interface = CreateDummyClass(interface_name, script);
+  interfaces.SetAt(0, Type::Handle(Type::NewNonParameterizedType(interface)));
+  interface_name = Symbols::New("Norton");
+  interface = CreateDummyClass(interface_name, script);
+  interfaces.SetAt(1, Type::Handle(Type::NewNonParameterizedType(interface)));
+  cls.set_interfaces(interfaces);
+
+  // Finalization of types happens before the fields and functions have been
+  // parsed.
+  ClassFinalizer::FinalizeTypesInClass(cls);
 
   // Create and populate the function arrays.
   const Array& functions = Array::Handle(Array::New(6));
@@ -79,19 +96,10 @@
       true, false, false, false, cls, 0);
   functions.SetAt(5, function);
 
-  // Setup the functions and interfaces in the class.
+  // Setup the functions in the class.
   cls.SetFunctions(functions);
-  const Array& interfaces = Array::Handle(Array::New(2));
-  Class& interface = Class::Handle();
-  String& interface_name = String::Handle();
-  interface_name = Symbols::New("Harley");
-  interface = CreateDummyClass(interface_name, script);
-  interfaces.SetAt(0, Type::Handle(Type::NewNonParameterizedType(interface)));
-  interface_name = Symbols::New("Norton");
-  interface = CreateDummyClass(interface_name, script);
-  interfaces.SetAt(1, Type::Handle(Type::NewNonParameterizedType(interface)));
-  cls.set_interfaces(interfaces);
-  ClassFinalizer::FinalizeTypesInClass(cls);
+
+  // The class can now be finalized.
   cls.Finalize();
 
   function_name = String::New("Foo");
@@ -176,10 +184,13 @@
   const Class& empty_class =
       Class::Handle(CreateDummyClass(class_name, script));
 
-  // No functions and no super class for the EmptyClass.
-  empty_class.SetFields(Object::empty_array());
+  // EmptyClass has no fields and no functions.
+  EXPECT_EQ(Array::Handle(empty_class.fields()).Length(), 0);
+  EXPECT_EQ(Array::Handle(empty_class.functions()).Length(), 0);
+
   ClassFinalizer::FinalizeTypesInClass(empty_class);
   empty_class.Finalize();
+
   EXPECT_EQ(kObjectAlignment, empty_class.instance_size());
   Instance& instance = Instance::Handle(Instance::New(empty_class));
   EXPECT_EQ(empty_class.raw(), instance.clazz());
@@ -188,14 +199,18 @@
   const Class& one_field_class =
       Class::Handle(CreateDummyClass(class_name, script));
 
-  // No functions and no super class for the OneFieldClass.
+  // No fields, functions, or super type for the OneFieldClass.
+  EXPECT_EQ(Array::Handle(empty_class.fields()).Length(), 0);
+  EXPECT_EQ(Array::Handle(empty_class.functions()).Length(), 0);
+  EXPECT_EQ(empty_class.super_type(), AbstractType::null());
+  ClassFinalizer::FinalizeTypesInClass(one_field_class);
+
   const Array& one_fields = Array::Handle(Array::New(1));
   const String& field_name = String::Handle(Symbols::New("the_field"));
   const Field& field = Field::Handle(
        Field::New(field_name, false, false, false, one_field_class, 0));
   one_fields.SetAt(0, field);
   one_field_class.SetFields(one_fields);
-  ClassFinalizer::FinalizeTypesInClass(one_field_class);
   one_field_class.Finalize();
   intptr_t header_size = sizeof(RawObject);
   EXPECT_EQ(Utils::RoundUp((header_size + (1 * kWordSize)), kObjectAlignment),
@@ -3214,6 +3229,14 @@
 }
 
 
+static RawFunction* GetStaticFunction(const Class& cls, const char* name) {
+  const Function& result = Function::Handle(cls.LookupStaticFunction(
+      String::Handle(String::New(name))));
+  EXPECT(!result.IsNull());
+  return result.raw();
+}
+
+
 static RawField* GetField(const Class& cls, const char* name) {
   const Field& field =
       Field::Handle(cls.LookupField(String::Handle(String::New(name))));
@@ -3325,28 +3348,40 @@
 TEST_CASE(FunctionSourceFingerprint) {
   const char* kScriptChars =
       "class A {\n"
-      "  void test1(int a) {\n"
+      "  static void test1(int a) {\n"
       "    return a > 1 ? a + 1 : a;\n"
       "  }\n"
-      "  void test2(int a) {\n"
+      "  static void test2(a) {\n"
       "    return a > 1 ? a + 1 : a;\n"
       "  }\n"
-      "  void test3(a) {\n"
-      "    return a > 1 ? a + 1 : a;\n"
-      "  }\n"
-      "  void test4(b) {\n"
+      "  static void test3(b) {\n"
       "    return b > 1 ? b + 1 : b;\n"
       "  }\n"
-      "  void test5(b) {\n"
+      "  static void test4(b) {\n"
       "    return b > 1 ? b - 1 : b;\n"
       "  }\n"
-      "  void test6(b) {\n"
+      "  static void test5(b) {\n"
       "    return b > 1 ? b - 2 : b;\n"
       "  }\n"
-      "  void test7(b) {\n"
+      "  void test6(int a) {\n"
+      "    return a > 1 ? a + 1 : a;\n"
+      "  }\n"
+      "}\n"
+      "class B {\n"
+      "  static void /* Different declaration style. */\n"
+      "  test1(int a) {\n"
+      "    /* Returns a + 1 for a > 1, a otherwise. */\n"
+      "    return a > 1 ?\n"
+      "        a + 1 :\n"
+      "        a;\n"
+      "  }\n"
+      "  static void test5(b) {\n"
       "    return b > 1 ?\n"
       "        b - 2 : b;\n"
       "  }\n"
+      "  void test6(int a) {\n"
+      "    return a > 1 ? a + 1 : a;\n"
+      "  }\n"
       "}";
   TestCase::LoadTestScript(kScriptChars, NULL);
   EXPECT(ClassFinalizer::FinalizePendingClasses());
@@ -3356,19 +3391,65 @@
 
   const Class& class_a = Class::Handle(
       lib.LookupClass(String::Handle(Symbols::New("A")), NULL));
-  const Function& test1 = Function::Handle(GetFunction(class_a, "test1"));
-  const Function& test2 = Function::Handle(GetFunction(class_a, "test2"));
-  const Function& test3 = Function::Handle(GetFunction(class_a, "test3"));
-  const Function& test4 = Function::Handle(GetFunction(class_a, "test4"));
-  const Function& test5 = Function::Handle(GetFunction(class_a, "test5"));
-  const Function& test6 = Function::Handle(GetFunction(class_a, "test6"));
-  const Function& test7 = Function::Handle(GetFunction(class_a, "test7"));
-  EXPECT_EQ(test1.SourceFingerprint(), test2.SourceFingerprint());
-  EXPECT_NE(test1.SourceFingerprint(), test3.SourceFingerprint());
-  EXPECT_NE(test3.SourceFingerprint(), test4.SourceFingerprint());
-  EXPECT_NE(test4.SourceFingerprint(), test5.SourceFingerprint());
-  EXPECT_NE(test5.SourceFingerprint(), test6.SourceFingerprint());
-  EXPECT_EQ(test6.SourceFingerprint(), test7.SourceFingerprint());
+  const Class& class_b = Class::Handle(
+      lib.LookupClass(String::Handle(Symbols::New("B")), NULL));
+  const Function& a_test1 =
+      Function::Handle(GetStaticFunction(class_a, "test1"));
+  const Function& b_test1 =
+      Function::Handle(GetStaticFunction(class_b, "test1"));
+  const Function& a_test2 =
+      Function::Handle(GetStaticFunction(class_a, "test2"));
+  const Function& a_test3 =
+      Function::Handle(GetStaticFunction(class_a, "test3"));
+  const Function& a_test4 =
+      Function::Handle(GetStaticFunction(class_a, "test4"));
+  const Function& a_test5 =
+      Function::Handle(GetStaticFunction(class_a, "test5"));
+  const Function& b_test5 =
+      Function::Handle(GetStaticFunction(class_b, "test5"));
+  const Function& a_test6 =
+      Function::Handle(GetFunction(class_a, "test6"));
+  const Function& b_test6 =
+      Function::Handle(GetFunction(class_b, "test6"));
+
+  EXPECT_EQ(a_test1.SourceFingerprint(), b_test1.SourceFingerprint());
+  EXPECT_NE(a_test1.SourceFingerprint(), a_test2.SourceFingerprint());
+  EXPECT_NE(a_test2.SourceFingerprint(), a_test3.SourceFingerprint());
+  EXPECT_NE(a_test3.SourceFingerprint(), a_test4.SourceFingerprint());
+  EXPECT_NE(a_test4.SourceFingerprint(), a_test5.SourceFingerprint());
+  EXPECT_EQ(a_test5.SourceFingerprint(), b_test5.SourceFingerprint());
+  EXPECT_NE(a_test6.SourceFingerprint(), b_test6.SourceFingerprint());
+}
+
+
+TEST_CASE(SpecialClassesHaveEmptyArrays) {
+  ObjectStore* object_store = Isolate::Current()->object_store();
+  Class& cls = Class::Handle();
+  Object& array = Object::Handle();
+
+  cls = object_store->null_class();
+  array = cls.fields();
+  EXPECT(!array.IsNull());
+  EXPECT(array.IsArray());
+  array = cls.functions();
+  EXPECT(!array.IsNull());
+  EXPECT(array.IsArray());
+
+  cls = Object::void_class();
+  array = cls.fields();
+  EXPECT(!array.IsNull());
+  EXPECT(array.IsArray());
+  array = cls.functions();
+  EXPECT(!array.IsNull());
+  EXPECT(array.IsArray());
+
+  cls = Object::dynamic_class();
+  array = cls.fields();
+  EXPECT(!array.IsNull());
+  EXPECT(array.IsArray());
+  array = cls.functions();
+  EXPECT(!array.IsNull());
+  EXPECT(array.IsArray());
 }
 
 }  // namespace dart
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 1060121..a63642d 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -456,7 +456,7 @@
     this->parameters->Add(param);
   }
 
-  void AddReceiver(const Type* receiver_type, intptr_t token_pos) {
+  void AddReceiver(const AbstractType* receiver_type, intptr_t token_pos) {
     ASSERT(this->parameters->is_empty());
     AddFinalParameter(token_pos, &Symbols::This(), receiver_type);
   }
@@ -526,6 +526,7 @@
   Token::Kind operator_token;
   const AbstractType* type;
   intptr_t name_pos;
+  intptr_t decl_begin_pos;
   String* name;
   // For constructors: NULL or name of redirected to constructor.
   String* redirect_name;
@@ -764,6 +765,9 @@
     case RawFunction::kConstructor:
       // The call to a redirecting factory is redirected.
       ASSERT(!func.IsRedirectingFactory());
+      if (!func.IsImplicitConstructor()) {
+        parser.SkipFunctionPreamble();
+      }
       node_sequence = parser.ParseFunc(func, default_parameter_values);
       break;
     case RawFunction::kImplicitGetter:
@@ -1016,7 +1020,7 @@
   // func.token_pos() points to the name of the field.
   intptr_t ident_pos = func.token_pos();
   ASSERT(current_class().raw() == func.Owner());
-  params.AddReceiver(ReceiverType(), ident_pos);
+  params.AddReceiver(ReceiverType(current_class()), ident_pos);
   ASSERT(func.num_fixed_parameters() == 1);  // receiver.
   ASSERT(!func.HasOptionalParameters());
   ASSERT(AbstractType::Handle(func.result_type()).IsResolved());
@@ -1060,7 +1064,7 @@
 
   ParamList params;
   ASSERT(current_class().raw() == func.Owner());
-  params.AddReceiver(ReceiverType(), ident_pos);
+  params.AddReceiver(ReceiverType(current_class()), ident_pos);
   params.AddFinalParameter(ident_pos,
                            &Symbols::Value(),
                            &field_type);
@@ -1093,7 +1097,7 @@
   const intptr_t ident_pos = func.token_pos();
   ASSERT(func.token_pos() == 0);
   ASSERT(current_class().raw() == func.Owner());
-  params.AddReceiver(ReceiverType(), ident_pos);
+  params.AddReceiver(ReceiverType(current_class()), ident_pos);
   ASSERT(func.num_fixed_parameters() == 1);  // Receiver.
   ASSERT(!func.HasOptionalParameters());
 
@@ -1123,7 +1127,7 @@
   ParamList params;
   // Receiver first.
   intptr_t token_pos = func.token_pos();
-  params.AddReceiver(ReceiverType(), token_pos);
+  params.AddReceiver(ReceiverType(current_class()), token_pos);
   // Remaining positional parameters.
   intptr_t i = 1;
   for (; i < desc.PositionalCount(); ++i) {
@@ -2283,20 +2287,16 @@
 
 SequenceNode* Parser::MakeImplicitConstructor(const Function& func) {
   ASSERT(func.IsConstructor());
+  ASSERT(func.Owner() == current_class().raw());
   const intptr_t ctor_pos = TokenPos();
   OpenFunctionBlock(func);
-  const Class& cls = Class::Handle(func.Owner());
 
   LocalVariable* receiver = new LocalVariable(
-      ctor_pos,
-      Symbols::This(),
-      Type::ZoneHandle(Type::DynamicType()));
+      ctor_pos, Symbols::This(), *ReceiverType(current_class()));
   current_block_->scope->AddVariable(receiver);
 
   LocalVariable* phase_parameter = new LocalVariable(
-       ctor_pos,
-       Symbols::PhaseParameter(),
-       Type::ZoneHandle(Type::SmiType()));
+      ctor_pos, Symbols::PhaseParameter(), Type::ZoneHandle(Type::SmiType()));
   current_block_->scope->AddVariable(phase_parameter);
 
   // Parse expressions of instance fields that have an explicit
@@ -2304,7 +2304,8 @@
   // The receiver must not be visible to field initializer expressions.
   receiver->set_invisible(true);
   GrowableArray<Field*> initialized_fields;
-  ParseInitializedInstanceFields(cls, receiver, &initialized_fields);
+  ParseInitializedInstanceFields(
+      current_class(), receiver, &initialized_fields);
   receiver->set_invisible(false);
 
   // If the class of this implicit constructor is a mixin application class,
@@ -2313,7 +2314,7 @@
   // expressions and then calls the respective super constructor with
   // the same name and number of parameters.
   ArgumentListNode* forwarding_args = NULL;
-  if (cls.mixin() != Type::null()) {
+  if (current_class().mixin() != Type::null()) {
     // At this point we don't support forwarding constructors
     // that have optional parameters because we don't know the default
     // values of the optional parameters. We would have to compile the super
@@ -2339,8 +2340,8 @@
     }
   }
 
-  GenerateSuperConstructorCall(cls, receiver, forwarding_args);
-  CheckConstFieldsInitialized(cls);
+  GenerateSuperConstructorCall(current_class(), receiver, forwarding_args);
+  CheckConstFieldsInitialized(current_class());
 
   // Empty constructor body.
   SequenceNode* statements = CloseBlock();
@@ -2388,7 +2389,7 @@
   // Add implicit receiver parameter which is passed the allocated
   // but uninitialized instance to construct.
   ASSERT(current_class().raw() == func.Owner());
-  params.AddReceiver(ReceiverType(), func.token_pos());
+  params.AddReceiver(ReceiverType(current_class()), func.token_pos());
 
   // Add implicit parameter for construction phase.
   params.AddFinalParameter(
@@ -2610,21 +2611,7 @@
       Function::Handle(innermost_function().raw());
   innermost_function_ = func.raw();
 
-  // Check to ensure we don't have classes with native fields in libraries
-  // which do not have a native resolver. This check is delayed until the class
-  // is actually used. Invocation of a function in the class is the first point
-  // of use. Access of const static fields in the class do not trigger an error.
-  if (current_class().num_native_fields() != 0) {
-    const Library& lib = Library::Handle(current_class().library());
-    if (lib.native_entry_resolver() == NULL) {
-      const String& cls_name = String::Handle(current_class().Name());
-      const String& lib_name = String::Handle(lib.url());
-      ErrorMsg(current_class().token_pos(),
-               "class '%s' is trying to extend a native fields class, "
-               "but library '%s' has no native resolvers",
-               cls_name.ToCString(), lib_name.ToCString());
-    }
-  }
+  // TODO(12455) : Need better validation mechanism.
 
   if (func.IsConstructor()) {
     SequenceNode* statements = ParseConstructor(func, default_parameter_values);
@@ -2648,7 +2635,7 @@
   } else if (!func.is_static()) {
     // Static functions do not have a receiver.
     ASSERT(current_class().raw() == func.Owner());
-    params.AddReceiver(ReceiverType(), func.token_pos());
+    params.AddReceiver(ReceiverType(current_class()), func.token_pos());
   } else if (func.IsFactory()) {
     // The first parameter of a factory is the AbstractTypeArguments vector of
     // the type of the instance to be allocated.
@@ -2835,7 +2822,6 @@
 void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) {
   TRACE_PARSER("ParseMethodOrConstructor");
   ASSERT(CurrentToken() == Token::kLPAREN || method->IsGetter());
-  intptr_t method_pos = this->TokenPos();
   ASSERT(method->type != NULL);
   ASSERT(method->name_pos > 0);
   ASSERT(current_member_ == method);
@@ -2870,7 +2856,7 @@
   // The first parameter of a factory is the AbstractTypeArguments vector of
   // the type of the instance to be allocated.
   if (!method->has_static || method->IsConstructor()) {
-    method->params.AddReceiver(ReceiverType(), formal_param_pos);
+    method->params.AddReceiver(ReceiverType(current_class()), formal_param_pos);
   } else if (method->IsFactory()) {
     method->params.AddFinalParameter(
         formal_param_pos,
@@ -3089,7 +3075,7 @@
                     method->has_abstract,
                     method->has_external,
                     current_class(),
-                    method_pos));
+                    method->decl_begin_pos));
   func.set_result_type(*method->type);
   func.set_end_token_pos(method_end_pos);
   if (method->metadata_pos > 0) {
@@ -3148,20 +3134,21 @@
     if (has_initializer) {
       ConsumeToken();
       init_value = Object::sentinel().raw();
-      // For static const fields, the initialization expression
-      // will be parsed through the kImplicitStaticFinalGetter method
-      // invocation/compilation.
+      // For static const fields and static final non-const fields, the
+      // initialization expression will be parsed through the
+      // kImplicitStaticFinalGetter method invocation/compilation.
       // For instance fields, the expression is parsed when a constructor
       // is compiled.
-      // For static const fields with very simple initializer expressions
-      // (e.g. a literal number or string) we optimize away the
-      // kImplicitStaticFinalGetter and initialize the field here.
-      // We also do it for static final non-const fields, but only in production
-      // mode.
+      // For static const fields and static final non-const fields with very
+      // simple initializer expressions (e.g. a literal number or string), we
+      // optimize away the kImplicitStaticFinalGetter and initialize the field
+      // here. However, the class finalizer will check the value type for
+      // assignability once the declared field type can be resolved. If the
+      // value is not assignable (assuming checked mode and disregarding actual
+      // mode), the field value is reset and a kImplicitStaticFinalGetter is
+      // created at finalization time.
 
-      if (field->has_static &&
-          (field->has_const ||
-           (!FLAG_enable_type_checks && field->has_final)) &&
+      if (field->has_static && (field->has_const || field->has_final) &&
           (LookaheadToken(1) == Token::kSEMICOLON)) {
         has_simple_literal = IsSimpleLiteral(*field->type, &init_value);
       }
@@ -3221,7 +3208,7 @@
                              field->name_pos);
       ParamList params;
       ASSERT(current_class().raw() == getter.Owner());
-      params.AddReceiver(ReceiverType(), field->name_pos);
+      params.AddReceiver(ReceiverType(current_class()), field->name_pos);
       getter.set_result_type(*field->type);
       AddFormalParamsToFunction(&params, getter);
       members->AddFunction(getter);
@@ -3237,7 +3224,7 @@
                                field->name_pos);
         ParamList params;
         ASSERT(current_class().raw() == setter.Owner());
-        params.AddReceiver(ReceiverType(), field->name_pos);
+        params.AddReceiver(ReceiverType(current_class()), field->name_pos);
         params.AddFinalParameter(TokenPos(),
                                  &Symbols::Value(),
                                  field->type);
@@ -3285,6 +3272,7 @@
   MemberDesc member;
   current_member_ = &member;
   member.metadata_pos = metadata_pos;
+  member.decl_begin_pos = TokenPos();
   if ((CurrentToken() == Token::kEXTERNAL) &&
       (LookaheadToken(1) != Token::kLPAREN)) {
     ConsumeToken();
@@ -3368,22 +3356,26 @@
         ErrorMsg(member.name_pos, "factory name must be '%s'",
                  members->class_name().ToCString());
       }
-      // Do not bypass class resolution by using current_class() directly, since
-      // it may be a patch class.
-      const Object& result_type_class = Object::Handle(
-          UnresolvedClass::New(LibraryPrefix::Handle(),
-                               *member.name,
-                               member.name_pos));
-      // The type arguments of the result type are the type parameters of the
-      // current class. Note that in the case of a patch class, they are copied
-      // from the class being patched.
-      member.type = &Type::ZoneHandle(Type::New(
-          result_type_class,
-          TypeArguments::Handle(current_class().type_parameters()),
-          member.name_pos));
     } else if (member.has_static) {
       ErrorMsg(member.name_pos, "constructor cannot be static");
     }
+    if (member.type != NULL) {
+      ErrorMsg(member.name_pos, "constructor must not specify return type");
+    }
+    // Do not bypass class resolution by using current_class() directly, since
+    // it may be a patch class.
+    const Object& result_type_class = Object::Handle(
+        UnresolvedClass::New(LibraryPrefix::Handle(),
+                             *member.name,
+                             member.name_pos));
+    // The type arguments of the result type are the type parameters of the
+    // current class. Note that in the case of a patch class, they are copied
+    // from the class being patched.
+    member.type = &Type::ZoneHandle(Type::New(
+        result_type_class,
+        TypeArguments::Handle(current_class().type_parameters()),
+        member.name_pos));
+
     // We must be dealing with a constructor or named constructor.
     member.kind = RawFunction::kConstructor;
     *member.name = String::Concat(*member.name, Symbols::Dot());
@@ -3395,18 +3387,7 @@
     }
     // Ensure that names are symbols.
     *member.name = Symbols::New(*member.name);
-    if (member.type == NULL) {
-      ASSERT(!member.has_factory);
-      // The body of the constructor cannot modify the type arguments of the
-      // constructed instance, which is passed in as a hidden parameter.
-      // Therefore, there is no need to set the result type to be checked.
-      member.type = &Type::ZoneHandle(Type::DynamicType());
-    } else {
-      // The type can only be already set in the factory case.
-      if (!member.has_factory) {
-        ErrorMsg(member.name_pos, "constructor must not specify return type");
-      }
-    }
+
     if (CurrentToken() != Token::kLPAREN) {
       ErrorMsg("left parenthesis expected");
     }
@@ -3690,9 +3671,9 @@
     // The patched class must not be finalized yet.
     const Class& orig_class = Class::Cast(obj);
     ASSERT(!orig_class.is_finalized());
-    const char* err_msg = orig_class.ApplyPatch(cls);
-    if (err_msg != NULL) {
-      ErrorMsg(class_pos, "applying patch failed with '%s'", err_msg);
+    Error& error = Error::Handle();
+    if (!orig_class.ApplyPatch(cls, &error)) {
+      AppendErrorMsg(error, class_pos, "applying patch failed");
     }
   }
 }
@@ -3719,10 +3700,9 @@
   ctor.set_end_token_pos(ctor.token_pos());
 
   ParamList params;
-  // Add implicit 'this' parameter. We don't care about the specific type
-  // and just specify dynamic.
-  const Type& receiver_type = Type::Handle(Type::DynamicType());
-  params.AddReceiver(&receiver_type, cls.token_pos());
+  // Add implicit 'this' parameter.
+  const AbstractType* receiver_type = ReceiverType(cls);
+  params.AddReceiver(receiver_type, cls.token_pos());
   // Add implicit parameter for construction phase.
   params.AddFinalParameter(cls.token_pos(),
                            &Symbols::PhaseParameter(),
@@ -3731,7 +3711,7 @@
   AddFormalParamsToFunction(&params, ctor);
   // The body of the constructor cannot modify the type of the constructed
   // instance, which is passed in as the receiver.
-  ctor.set_result_type(receiver_type);
+  ctor.set_result_type(*receiver_type);
   cls.AddFunction(ctor);
 }
 
@@ -3822,7 +3802,9 @@
   mixin_application.set_super_type(type);
   mixin_application.set_is_synthesized_class();
 
-  AddImplicitConstructor(mixin_application);
+  // This mixin application typedef needs an implicit constructor, but it is
+  // too early to call 'AddImplicitConstructor(mixin_application)' here,
+  // because this class should be lazily compiled.
   if (CurrentToken() == Token::kIMPLEMENTS) {
     ParseInterfaceList(mixin_application);
   }
@@ -4257,10 +4239,8 @@
   // Const fields are implicitly final.
   const bool is_final = is_const || (CurrentToken() == Token::kFINAL);
   const bool is_static = true;
-  const AbstractType& type =
-      AbstractType::ZoneHandle(ParseConstFinalVarOrType(
-          FLAG_enable_type_checks ? ClassFinalizer::kResolveTypeParameters :
-                                    ClassFinalizer::kIgnore));
+  const AbstractType& type = AbstractType::ZoneHandle(ParseConstFinalVarOrType(
+      ClassFinalizer::kResolveTypeParameters));
   Field& field = Field::Handle();
   Function& getter = Function::Handle();
   while (true) {
@@ -4298,15 +4278,14 @@
       ConsumeToken();
       Instance& field_value = Instance::Handle(Object::sentinel().raw());
       bool has_simple_literal = false;
-      if ((is_const || (!FLAG_enable_type_checks && is_final)) &&
-          (LookaheadToken(1) == Token::kSEMICOLON)) {
+      if ((is_const || is_final) && (LookaheadToken(1) == Token::kSEMICOLON)) {
         has_simple_literal = IsSimpleLiteral(type, &field_value);
       }
       SkipExpr();
       field.set_value(field_value);
       if (!has_simple_literal) {
-        // Create a static const getter.
-        String& getter_name = String::ZoneHandle(Field::GetterSymbol(var_name));
+        // Create a static final getter.
+        String& getter_name = String::Handle(Field::GetterSymbol(var_name));
         getter = Function::New(getter_name,
                                RawFunction::kImplicitStaticFinalGetter,
                                is_static,
@@ -4337,6 +4316,7 @@
 void Parser::ParseTopLevelFunction(TopLevel* top_level,
                                    intptr_t metadata_pos) {
   TRACE_PARSER("ParseTopLevelFunction");
+  const intptr_t decl_begin_pos = TokenPos();
   AbstractType& result_type = Type::Handle(Type::DynamicType());
   const bool is_static = true;
   bool is_external = false;
@@ -4410,7 +4390,7 @@
                     /* is_abstract = */ false,
                     is_external,
                     current_class(),
-                    function_pos));
+                    decl_begin_pos));
   func.set_result_type(result_type);
   func.set_end_token_pos(function_end_pos);
   AddFormalParamsToFunction(&params, func);
@@ -4429,6 +4409,7 @@
 void Parser::ParseTopLevelAccessor(TopLevel* top_level,
                                    intptr_t metadata_pos) {
   TRACE_PARSER("ParseTopLevelAccessor");
+  const intptr_t decl_begin_pos = TokenPos();
   const bool is_static = true;
   bool is_external = false;
   bool is_patch = false;
@@ -4535,7 +4516,7 @@
                     /* is_abstract = */ false,
                     is_external,
                     current_class(),
-                    accessor_pos));
+                    decl_begin_pos));
   func.set_result_type(result_type);
   func.set_end_token_pos(accessor_end_pos);
   AddFormalParamsToFunction(&params, func);
@@ -4960,7 +4941,10 @@
           params->has_optional_named_parameters));
   if (!Utils::IsInt(16, params->num_fixed_parameters) ||
       !Utils::IsInt(16, params->num_optional_parameters)) {
-    ErrorMsg(func.token_pos(), "too many formal parameters");
+    const Script& script = Script::Handle(Class::Handle(func.Owner()).script());
+    const Error& error = Error::Handle(FormatErrorMsg(
+        script, func.token_pos(), "Error", "too many formal parameters"));
+    ErrorMsg(error);
   }
   func.set_num_fixed_parameters(params->num_fixed_parameters);
   func.SetNumOptionalParameters(params->num_optional_parameters,
@@ -4973,7 +4957,6 @@
                                                     Heap::kOld)));
   for (int i = 0; i < num_parameters; i++) {
     ParamDesc& param_desc = (*params->parameters)[i];
-    ASSERT(is_top_level_ || param_desc.type->IsResolved());
     func.SetParameterTypeAt(i, *param_desc.type);
     func.SetParameterNameAt(i, *param_desc.name);
   }
@@ -5249,7 +5232,6 @@
                (LookaheadToken(1) != Token::kLPAREN)) {
       result_type = ParseType(ClassFinalizer::kCanonicalize);
     }
-    ident_pos = TokenPos();
     variable_name = ExpectIdentifier("function name expected");
     function_name = variable_name;
   }
@@ -5275,7 +5257,7 @@
     is_new_closure = true;
     function = Function::NewClosureFunction(*function_name,
                                             innermost_function(),
-                                            function_pos);
+                                            ident_pos);
     function.set_result_type(result_type);
     current_class().AddClosureFunction(function);
   }
@@ -6940,7 +6922,7 @@
 
 
 void Parser::ErrorMsg(const Error& error) {
-  isolate()->long_jump_base()->Jump(1, error);
+  Isolate::Current()->long_jump_base()->Jump(1, error);
   UNREACHABLE();
 }
 
@@ -7292,6 +7274,29 @@
   if ((binary_op == Token::kAND) || (binary_op == Token::kOR)) {
     EnsureExpressionTemp();
   }
+  if (binary_op == Token::kBIT_AND) {
+    // Normalize so that rhs is a literal if any is.
+    if ((rhs_literal == NULL) && (lhs_literal != NULL)) {
+      // Swap.
+      LiteralNode* temp = rhs_literal;
+      rhs_literal = lhs_literal;
+      lhs_literal = temp;
+    }
+    if ((rhs_literal != NULL) &&
+        (rhs_literal->literal().IsSmi() || rhs_literal->literal().IsMint())) {
+      const int64_t val = Integer::Cast(rhs_literal->literal()).AsInt64Value();
+      if ((0 <= val) && (Utils::IsUint(32, val))) {
+        if (lhs->IsBinaryOpNode() &&
+            (lhs->AsBinaryOpNode()->kind() == Token::kSHL)) {
+          // Merge SHL and BIT_AND into one "SHL with mask" node.
+          BinaryOpNode* old = lhs->AsBinaryOpNode();
+          BinaryOpWithMask32Node* binop = new BinaryOpWithMask32Node(
+              old->token_pos(), old->kind(), old->left(), old->right(), val);
+          return binop;
+        }
+      }
+    }
+  }
   return new BinaryOpNode(op_pos, binary_op, lhs, rhs);
 }
 
@@ -8353,17 +8358,18 @@
 }
 
 
-const Type* Parser::ReceiverType() const {
-  ASSERT(!current_class().IsNull());
+const AbstractType* Parser::ReceiverType(const Class& cls) {
+  ASSERT(!cls.IsNull());
   TypeArguments& type_arguments = TypeArguments::Handle();
-  if (current_class().NumTypeParameters() > 0) {
-    type_arguments = current_class().type_parameters();
+  if (cls.NumTypeParameters() > 0) {
+    type_arguments = cls.type_parameters();
   }
-  Type& type = Type::ZoneHandle(
-      Type::New(current_class(), type_arguments, current_class().token_pos()));
-  if (!is_top_level_ || current_class().is_type_finalized()) {
+  AbstractType& type = AbstractType::ZoneHandle(
+      Type::New(cls, type_arguments, cls.token_pos()));
+  if (cls.is_type_finalized()) {
     type ^= ClassFinalizer::FinalizeType(
-        current_class(), type, ClassFinalizer::kCanonicalizeWellFormed);
+        cls, type, ClassFinalizer::kCanonicalizeWellFormed);
+    // Note that the receiver type may now be a malbounded type.
   }
   return &type;
 }
@@ -9243,7 +9249,6 @@
                             AstNode* value) {
   if (is_const) {
     ASSERT(key->IsLiteralNode());
-    ASSERT(key->AsLiteralNode()->literal().IsString());
     const Instance& new_key = key->AsLiteralNode()->literal();
     for (int i = 0; i < pairs->length(); i += 2) {
       const Instance& key_i =
@@ -10041,6 +10046,30 @@
 }
 
 
+// Skips function/method/constructor/getter/setter preambles until the formal
+// parameter list. It is enough to skip the tokens, since we have already
+// previously parsed the function.
+void Parser::SkipFunctionPreamble() {
+  while (true) {
+    if (CurrentToken() == Token::kLPAREN ||
+        CurrentToken() == Token::kARROW ||
+        CurrentToken() == Token::kSEMICOLON ||
+        CurrentToken() == Token::kLBRACE) {
+      return;
+    }
+    // Case handles "native" keyword, but also return types of form
+    // native.SomeType where native is the name of a library.
+    if (CurrentToken() == Token::kIDENT &&
+        LookaheadToken(1) != Token::kPERIOD) {
+      if (CurrentLiteral()->raw() == Symbols::Native().raw()) {
+        return;
+      }
+    }
+    ConsumeToken();
+  }
+}
+
+
 void Parser::SkipListLiteral() {
   if (CurrentToken() == Token::kINDEX) {
     // Empty list literal.
@@ -10052,6 +10081,8 @@
     SkipNestedExpr();
     if (CurrentToken() == Token::kCOMMA) {
       ConsumeToken();
+    } else {
+      break;
     }
   }
   ExpectToken(Token::kRBRACK);
@@ -10060,12 +10091,14 @@
 
 void Parser::SkipMapLiteral() {
   ExpectToken(Token::kLBRACE);
-  while (CurrentToken() == Token::kSTRING) {
-    SkipStringLiteral();
+  while (CurrentToken() != Token::kRBRACE) {
+    SkipNestedExpr();
     ExpectToken(Token::kCOLON);
     SkipNestedExpr();
     if (CurrentToken() == Token::kCOMMA) {
       ConsumeToken();
+    } else {
+      break;
     }
   }
   ExpectToken(Token::kRBRACE);
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 92c30cb..2af08c2 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -162,7 +162,7 @@
                                   intptr_t token_pos,
                                   const char* message_header,
                                   const char* format, ...)
-    PRINTF_ATTRIBUTE(4, 5);
+      PRINTF_ATTRIBUTE(4, 5);
 
   // Same as FormatError, but appends the new error to the 'prev_error'.
   static RawError* FormatErrorWithAppend(const Error& prev_error,
@@ -172,6 +172,8 @@
                                          const char* format,
                                          va_list args);
 
+  static void AddImplicitConstructor(const Class& cls);
+
  private:
   friend class EffectGraphVisitor;  // For BuildNoSuchMethodArguments.
 
@@ -285,6 +287,7 @@
   void SkipFunctionLiteral();
   void SkipStringLiteral();
   void SkipQualIdent();
+  void SkipFunctionPreamble();
 
   void CheckConstructorCallTypeArguments(
     intptr_t pos,
@@ -298,19 +301,19 @@
                                   const char* format,
                                   va_list args);
 
-  // Reports error/warning message at location of current token.
+  // Reports error/warning msg at location of current token in current script.
   void ErrorMsg(const char* msg, ...) PRINTF_ATTRIBUTE(2, 3);
   void Warning(const char* msg, ...)  PRINTF_ATTRIBUTE(2, 3);
   void Unimplemented(const char* msg);
 
-  // Reports error message at given location.
+  // Reports error message at given location in current script.
   void ErrorMsg(intptr_t token_pos, const char* msg, ...) const
       PRINTF_ATTRIBUTE(3, 4);
   void Warning(intptr_t token_pos, const char* msg, ...)
       PRINTF_ATTRIBUTE(3, 4);
 
   // Reports an already formatted error message.
-  void ErrorMsg(const Error& error);
+  static void ErrorMsg(const Error& error);
 
   // Concatenates two error messages, the previous and the current one.
   void AppendErrorMsg(
@@ -371,7 +374,6 @@
   void ParseFormalParameterList(bool allow_explicit_default_values,
                                 ParamList* params);
   void CheckConstFieldsInitialized(const Class& cls);
-  void AddImplicitConstructor(const Class& cls);
   void CheckConstructors(ClassDesc* members);
   AstNode* ParseExternalInitializedField(const Field& field);
   void ParseInitializedInstanceFields(
@@ -422,7 +424,8 @@
   AstNode* CreateImplicitClosureNode(const Function& func,
                                      intptr_t token_pos,
                                      AstNode* receiver);
-  void AddFormalParamsToFunction(const ParamList* params, const Function& func);
+  static void AddFormalParamsToFunction(const ParamList* params,
+                                        const Function& func);
   void AddFormalParamsToScope(const ParamList* params, LocalScope* scope);
 
   SequenceNode* ParseConstructor(const Function& func,
@@ -555,7 +558,7 @@
   LocalVariable* LookupLocalScope(const String& ident);
   void CheckInstanceFieldAccess(intptr_t field_pos, const String& field_name);
   bool ParsingStaticMember() const;
-  const Type* ReceiverType() const;
+  static const AbstractType* ReceiverType(const Class& cls);
   bool IsInstantiatorRequired() const;
   bool ResolveIdentInLocalScope(intptr_t ident_pos,
                                 const String &ident,
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index b8ecacb..7483d21 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -772,14 +772,6 @@
 }
 
 
-intptr_t RawDartFunction::VisitDartFunctionPointers(
-    RawDartFunction* raw_obj, ObjectPointerVisitor* visitor) {
-  // Function (defined in core library) is an abstract class.
-  UNREACHABLE();
-  return 0;
-}
-
-
 intptr_t RawStacktrace::VisitStacktracePointers(RawStacktrace* raw_obj,
                                                 ObjectPointerVisitor* visitor) {
   // Make sure that we got here with the tagged pointer as this.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 08a6516..6d5892d 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -67,7 +67,6 @@
     V(JSRegExp)                                                                \
     V(WeakProperty)                                                            \
     V(MirrorReference)                                                         \
-    V(DartFunction)                                                            \
     V(Float32x4)                                                               \
     V(Uint32x4)                                                                \
 
@@ -1464,11 +1463,6 @@
 };
 
 
-class RawDartFunction : public RawInstance {
-  RAW_HEAP_OBJECT_IMPLEMENTATION(DartFunction);
-};
-
-
 // VM type for capturing stacktraces when exceptions are thrown,
 // Currently we don't have any interface that this object is supposed
 // to implement so we just support the 'toString' method which
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 11382c0..3e48cdb 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -48,7 +48,7 @@
       cls = reader->NewClass(class_id);
     } else {
       if (class_id < kNumPredefinedCids) {
-        ASSERT((class_id >= kInstanceCid) && (class_id <= kDartFunctionCid));
+        ASSERT((class_id >= kInstanceCid) && (class_id <= kMirrorReferenceCid));
         cls = reader->isolate()->class_table()->At(class_id);
       } else {
         cls = New<Instance>(kIllegalCid);
@@ -2473,22 +2473,6 @@
 #undef EXT_TYPED_DATA_WRITE
 
 
-RawDartFunction* DartFunction::ReadFrom(SnapshotReader* reader,
-                                        intptr_t object_id,
-                                        intptr_t tags,
-                                        Snapshot::Kind kind) {
-  UNREACHABLE();  // DartFunction is an abstract class.
-  return DartFunction::null();
-}
-
-
-void RawDartFunction::WriteTo(SnapshotWriter* writer,
-                              intptr_t object_id,
-                              Snapshot::Kind kind) {
-  UNREACHABLE();  // DartFunction is an abstract class.
-}
-
-
 RawStacktrace* Stacktrace::ReadFrom(SnapshotReader* reader,
                                     intptr_t object_id,
                                     intptr_t tags,
diff --git a/runtime/vm/reusable_handles.h b/runtime/vm/reusable_handles.h
new file mode 100644
index 0000000..2af338d
--- /dev/null
+++ b/runtime/vm/reusable_handles.h
@@ -0,0 +1,144 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_REUSABLE_HANDLES_H_
+#define VM_REUSABLE_HANDLES_H_
+
+#include "vm/allocation.h"
+#include "vm/handles.h"
+#include "vm/object.h"
+
+namespace dart {
+
+// The class ReusableHandleScope is used in regions of the
+// virtual machine where isolate specific reusable handles are used.
+// This class asserts that we do not add code that will result in recursive
+// uses of reusable handles.
+// It is used as follows:
+// {
+//   ReusableHandleScope reused_handles(isolate);
+//   ....
+//   .....
+//   code that uses isolate specific reusable handles.
+//   Array& funcs = reused_handles.ArrayHandle();
+//   ....
+// }
+#if defined(DEBUG)
+class ReusableObjectHandleScope : public StackResource {
+ public:
+  explicit ReusableObjectHandleScope(Isolate* isolate)
+      : StackResource(isolate), isolate_(isolate) {
+    ASSERT(!isolate->reusable_handle_scope_active());
+    isolate->set_reusable_handle_scope_active(true);
+  }
+  ReusableObjectHandleScope()
+      : StackResource(Isolate::Current()), isolate_(Isolate::Current()) {
+    ASSERT(!isolate()->reusable_handle_scope_active());
+    isolate()->set_reusable_handle_scope_active(true);
+  }
+  ~ReusableObjectHandleScope() {
+    ASSERT(isolate()->reusable_handle_scope_active());
+    isolate()->set_reusable_handle_scope_active(false);
+    Handle().raw_ = Object::null();
+  }
+  Object& Handle() {
+    ASSERT(isolate_->Object_handle_ != NULL);
+    return *isolate_->Object_handle_;
+  }
+
+ private:
+  Isolate* isolate_;
+  DISALLOW_COPY_AND_ASSIGN(ReusableObjectHandleScope);
+};
+
+
+class ReusableHandleScope : public StackResource {
+ public:
+  explicit ReusableHandleScope(Isolate* isolate)
+      : StackResource(isolate), isolate_(isolate) {
+    ASSERT(!isolate->reusable_handle_scope_active());
+    isolate->set_reusable_handle_scope_active(true);
+  }
+  ReusableHandleScope()
+      : StackResource(Isolate::Current()), isolate_(Isolate::Current()) {
+    ASSERT(!isolate()->reusable_handle_scope_active());
+    isolate()->set_reusable_handle_scope_active(true);
+  }
+  ~ReusableHandleScope() {
+    ASSERT(isolate()->reusable_handle_scope_active());
+    isolate()->set_reusable_handle_scope_active(false);
+#define CLEAR_REUSABLE_HANDLE(object)                                          \
+    object##Handle().raw_ = Object::null();                                    \
+
+    REUSABLE_HANDLE_LIST(CLEAR_REUSABLE_HANDLE);
+  }
+
+#define REUSABLE_HANDLE_ACCESSORS(object)                                      \
+  object& object##Handle() {                                                   \
+    ASSERT(isolate_->object##_handle_ != NULL);                                \
+    return *isolate_->object##_handle_;                                        \
+  }                                                                            \
+
+  REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ACCESSORS)
+#undef REUSABLE_HANDLE_ACCESSORS
+
+ private:
+  void ResetHandles();
+  Isolate* isolate_;
+  DISALLOW_COPY_AND_ASSIGN(ReusableHandleScope);
+};
+#else
+class ReusableObjectHandleScope : public ValueObject {
+ public:
+  explicit ReusableObjectHandleScope(Isolate* isolate)
+      : handle_(isolate->Object_handle_) {
+  }
+  ReusableObjectHandleScope() : handle_(Isolate::Current()->Object_handle_) {
+  }
+  ~ReusableObjectHandleScope() {
+    handle_->raw_ = Object::null();
+  }
+  Object& Handle() {
+    ASSERT(handle_ != NULL);
+    return *handle_;
+  }
+
+ private:
+  Object* handle_;
+  DISALLOW_COPY_AND_ASSIGN(ReusableObjectHandleScope);
+};
+
+
+class ReusableHandleScope : public ValueObject {
+ public:
+  explicit ReusableHandleScope(Isolate* isolate) : isolate_(isolate) {
+  }
+  ReusableHandleScope() : isolate_(Isolate::Current()) {
+  }
+  ~ReusableHandleScope() {
+#define CLEAR_REUSABLE_HANDLE(object)                                          \
+    object##Handle().raw_ = Object::null();                                    \
+
+    REUSABLE_HANDLE_LIST(CLEAR_REUSABLE_HANDLE);
+  }
+
+#define REUSABLE_HANDLE_ACCESSORS(object)                                      \
+  object& object##Handle() {                                                   \
+    ASSERT(isolate_->object##_handle_ != NULL);                                \
+    return *isolate_->object##_handle_;                                        \
+  }                                                                            \
+
+  REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ACCESSORS)
+#undef REUSABLE_HANDLE_ACCESSORS
+
+ private:
+  void ResetHandles();
+  Isolate* isolate_;
+  DISALLOW_COPY_AND_ASSIGN(ReusableHandleScope);
+};
+#endif  // defined(DEBUG)
+
+}  // namespace dart
+
+#endif  // VM_REUSABLE_HANDLES_H_
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index fff829a..8bf4926 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -581,7 +581,17 @@
         string_chars.Add(string_delimiter_);
       }
     } else {
-      string_chars.Add(c0_);
+      // Test for a two part utf16 sequence, and decode to a code point
+      // if we find one.
+      int32_t ch1 = c0_;
+      if (Utf16::IsLeadSurrogate(ch1)) {
+        const int32_t ch2 = LookaheadChar(1);
+        if (Utf16::IsTrailSurrogate(ch2)) {
+          ch1 = Utf16::Decode(ch1, ch2);
+          ReadChar();
+        }
+      }
+      string_chars.Add(ch1);
     }
     ReadChar();
   }
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index a6be317..d7e551b 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -65,8 +65,6 @@
   switch (index) {
     case kObjectType: return object_store->object_type();
     case kNullType: return object_store->null_type();
-    case kDynamicType: return object_store->dynamic_type();
-    case kVoidType: return object_store->void_type();
     case kFunctionType: return object_store->function_type();
     case kNumberType: return object_store->number_type();
     case kSmiType: return object_store->smi_type();
@@ -89,10 +87,6 @@
     return kObjectType;
   } else if (raw_type == object_store->null_type()) {
     return kNullType;
-  } else if (raw_type == object_store->dynamic_type()) {
-    return kDynamicType;
-  } else if (raw_type == object_store->void_type()) {
-    return kVoidType;
   } else if (raw_type == object_store->function_type()) {
     return kFunctionType;
   } else if (raw_type == object_store->number_type()) {
@@ -726,6 +720,12 @@
   if (object_id == kEmptyArrayObject) {
     return Object::empty_array().raw();
   }
+  if (object_id == kDynamicType) {
+    return Object::dynamic_type();
+  }
+  if (object_id == kVoidType) {
+    return Object::void_type();
+  }
   if (object_id == kTrueValue) {
     return Bool::True().raw();
   }
@@ -893,6 +893,18 @@
     return;
   }
 
+  // Check if it is a singleton dyanmic Type object.
+  if (rawobj == Object::dynamic_type()) {
+    WriteVMIsolateObject(kDynamicType);
+    return;
+  }
+
+  // Check if it is a singleton void Type object.
+  if (rawobj == Object::void_type()) {
+    WriteVMIsolateObject(kVoidType);
+    return;
+  }
+
   // Check if it is a singleton boolean true object.
   if (rawobj == Bool::True().raw()) {
     WriteVMIsolateObject(kTrueValue);
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index c1781d2..0758462 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -9,6 +9,7 @@
 #include "vm/dart_api_impl.h"
 #include "vm/dart_api_message.h"
 #include "vm/dart_api_state.h"
+#include "vm/flags.h"
 #include "vm/snapshot.h"
 #include "vm/symbols.h"
 #include "vm/unicode.h"
@@ -16,6 +17,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, enable_type_checks);
+
 // Check if serialized and deserialized objects are equal.
 static bool Equals(const Object& expected, const Object& actual) {
   if (expected.IsNull()) {
@@ -1227,6 +1230,112 @@
 }
 
 
+UNIT_TEST_CASE(ScriptSnapshot2) {
+  // The snapshot of this library is always created in production mode, but
+  // loaded and executed in both production and checked modes.
+  // This test verifies that type information is still contained in the snapshot
+  // although it was created in production mode and that type errors and
+  // compilation errors (for const fields) are correctly reported according to
+  // the execution mode.
+  const char* kLibScriptChars =
+      "library dart_import_lib;"
+      "const String s = 1.0;"
+      "final int i = true;"
+      "bool b;";
+  const char* kScriptChars =
+      "test_s() {"
+      "  s;"
+      "}"
+      "test_i() {"
+      "  i;"
+      "}"
+      "test_b() {"
+      "  b = 0;"
+      "}";
+  Dart_Handle result;
+
+  uint8_t* buffer;
+  intptr_t size;
+  uint8_t* full_snapshot = NULL;
+  uint8_t* script_snapshot = NULL;
+
+  // Force creation of snapshot in production mode.
+  bool saved_mode = FLAG_enable_type_checks;
+  FLAG_enable_type_checks = false;
+
+  {
+    // Start an Isolate, and create a full snapshot of it.
+    TestIsolateScope __test_isolate__;
+    Dart_EnterScope();  // Start a Dart API scope for invoking API functions.
+
+    // Write out the script snapshot.
+    result = Dart_CreateSnapshot(&buffer, &size);
+    EXPECT_VALID(result);
+    full_snapshot = reinterpret_cast<uint8_t*>(malloc(size));
+    memmove(full_snapshot, buffer, size);
+    Dart_ExitScope();
+  }
+
+  {
+    // Create an Isolate using the full snapshot, load a script and create
+    // a script snapshot of the script.
+    TestCase::CreateTestIsolateFromSnapshot(full_snapshot);
+    Dart_EnterScope();  // Start a Dart API scope for invoking API functions.
+
+    // Load the library.
+    Dart_Handle import_lib = Dart_LoadLibrary(NewString("dart_import_lib"),
+                                              NewString(kLibScriptChars));
+    EXPECT_VALID(import_lib);
+
+    // Create a test library and Load up a test script in it.
+    TestCase::LoadTestScript(kScriptChars, NULL);
+
+    EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
+                                           import_lib,
+                                           Dart_Null()));
+    EXPECT_VALID(Api::CheckIsolateState(Isolate::Current()));
+
+    // Write out the script snapshot.
+    result = Dart_CreateScriptSnapshot(&buffer, &size);
+    EXPECT_VALID(result);
+    script_snapshot = reinterpret_cast<uint8_t*>(malloc(size));
+    memmove(script_snapshot, buffer, size);
+    Dart_ExitScope();
+    Dart_ShutdownIsolate();
+  }
+
+  // Continue in originally saved mode.
+  FLAG_enable_type_checks = saved_mode;
+
+  {
+    // Now Create an Isolate using the full snapshot and load the
+    // script snapshot created above and execute it.
+    TestCase::CreateTestIsolateFromSnapshot(full_snapshot);
+    Dart_EnterScope();  // Start a Dart API scope for invoking API functions.
+
+    // Load the test library from the snapshot.
+    EXPECT(script_snapshot != NULL);
+    Dart_Handle lib = Dart_LoadScriptFromSnapshot(script_snapshot, size);
+    EXPECT_VALID(lib);
+
+    // Invoke the test_s function.
+    result = Dart_Invoke(lib, NewString("test_s"), 0, NULL);
+    EXPECT(Dart_IsError(result) == saved_mode);
+
+    // Invoke the test_i function.
+    result = Dart_Invoke(lib, NewString("test_i"), 0, NULL);
+    EXPECT(Dart_IsError(result) == saved_mode);
+
+    // Invoke the test_b function.
+    result = Dart_Invoke(lib, NewString("test_b"), 0, NULL);
+    EXPECT(Dart_IsError(result) == saved_mode);
+  }
+  Dart_ShutdownIsolate();
+  free(full_snapshot);
+  free(script_snapshot);
+}
+
+
 TEST_CASE(IntArrayMessage) {
   StackZone zone(Isolate::Current());
   uint8_t* buffer = NULL;
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index bdb2981..9be9e94 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -2174,13 +2174,15 @@
 // A1: stack_pointer.
 // A2: frame_pointer.
 // A3: error object.
-// SP: address of stacktrace object.
+// SP + 4*kWordSize: address of stacktrace object.
 // Does not return.
 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
   ASSERT(kExceptionObjectReg == V0);
   ASSERT(kStackTraceObjectReg == V1);
   __ mov(V0, A3);  // Exception object.
-  __ lw(V1, Address(SP, 0));  // StackTrace object.
+  // MIPS ABI reserves stack space for all arguments. The StackTrace object is
+  // the last of five arguments, so it is first pushed on the stack.
+  __ lw(V1, Address(SP, 4 * kWordSize));  // StackTrace object.
   __ mov(FP, A2);  // Frame_pointer.
   __ jr(A0);  // Jump to the exception handler code.
   __ delay_slot()->mov(SP, A1);  // Stack pointer.
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 35f7d79..c39133e 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -62,6 +62,7 @@
   V(ClosureFunctionField, ":function")                                         \
   V(ClosureContextField, ":context")                                           \
   V(Library, "library")                                                        \
+  V(Native, "native")                                                          \
   V(Import, "import")                                                          \
   V(Source, "source")                                                          \
   V(Class, "Class")                                                            \
@@ -77,6 +78,7 @@
   V(InstantiatedTypeArguments, "InstantiatedTypeArguments")                    \
   V(PatchClass, "PatchClass")                                                  \
   V(Function, "Function")                                                      \
+  V(FunctionImpl, "_FunctionImpl")                                             \
   V(FunctionResult, "function result")                                         \
   V(FactoryResult, "factory result")                                           \
   V(ClosureData, "ClosureData")                                                \
@@ -282,6 +284,7 @@
   V(_LocalMirrorSystemImpl, "_LocalMirrorSystemImpl")                          \
   V(_LocalTypedefMirrorImpl, "_LocalTypedefMirrorImpl")                        \
   V(_LocalTypeVariableMirrorImpl, "_LocalTypeVariableMirrorImpl")              \
+  V(_leftShiftWithMask32, "_leftShiftWithMask32")                              \
 
 
 // Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index cea087a..bb896d0 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -267,6 +267,7 @@
     'resolver.cc',
     'resolver.h',
     'resolver_test.cc',
+    'reusable_handles.h',
     'runtime_entry.h',
     'runtime_entry_arm.cc',
     'runtime_entry_ia32.cc',
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 88d35c5..3401be7 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -468,7 +468,12 @@
   static const int NO_SUCH_METHOD_ARG_COUNT = 1;
   static const SourceString CREATE_INVOCATION_MIRROR =
       const SourceString('createInvocationMirror');
-  static const SourceString INVOKE_ON = const SourceString('_invokeOn');
+
+  // TODO(ahe): Rename this field and move this logic to backend, similar to how
+  // we disable tree-shaking when seeing disableTreeShaking in js_mirrors.dart.
+  static const SourceString INVOKE_ON =
+      const SourceString('_getCachedInvocation');
+
   static const SourceString RUNTIME_TYPE = const SourceString('runtimeType');
   static const SourceString START_ROOT_ISOLATE =
       const SourceString('startRootIsolate');
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 21d5920..235a943 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -882,6 +882,8 @@
   void forEachStaticField(void f(ClassElement enclosingClass, Element field));
 
   void forEachBackendMember(void f(Element member));
+
+  Link<DartType> computeTypeParameters(Compiler compiler);
 }
 
 abstract class MixinApplicationElement extends ClassElement {
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index f750960..05c1d46 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -19,24 +19,22 @@
     void addMemberByName(Element element) {
       element = element.declaration;
       String name = element.name.slowToString();
-      Link<Element> members = const Link<Element>();
+      ScopeContainerElement container = null;
       if (element.isLibrary()) {
-        LibraryElementX library = element;
+        LibraryElement library = element;
         // Don't include private implementation libraries.  These
         // libraries contain special classes that cause problems
         // in other parts of the resolver (in particular Null and Void).
         // TODO(ahe): Consider lifting this restriction.
         if (!library.isInternalLibrary) {
-          members = library.localMembers;
+          container = library;
           // TODO(ahe): Is this right?  Is this necessary?
           name = library.getLibraryOrScriptName();
         }
-      } else if (element.isClass() && !element.isMixinApplication) {
-        // TODO(ahe): Investigate what makes mixin applications crash
-        // this method.
-        ClassElementX cls = element;
+      } else if (element.isClass()) {
+        ClassElement cls = element;
         cls.ensureResolved(compiler);
-        members = cls.localMembers;
+        container = cls;
         for (var link = cls.computeTypeParameters(compiler);
              !link.isEmpty;
              link = link.tail) {
@@ -45,8 +43,8 @@
       }
       allElementsByName[name] = allElementsByName.putIfAbsent(
           name, () => const Link<Element>()).prepend(element);
-      for (var link = members; !link.isEmpty; link = link.tail) {
-        addMemberByName(link.head);
+      if (container != null) {
+        container.forEachLocalMember(addMemberByName);
       }
     }
 
@@ -323,11 +321,9 @@
       ClassElement cls = element.declaration.getEnclosingClass();
       registerInstantiatedType(cls.rawType, elements);
       registerStaticUse(element.declaration);
-    } else if (element.isMixinApplication) {
-      // Don't enqueue mixin applications.
     } else if (element.isClass()) {
       ClassElement cls = element.declaration;
-      registerInstantiatedType(cls.rawType, elements);
+      registerInstantiatedClass(cls, elements);
       // Make sure that even abstract classes are considered instantiated.
       universe.instantiatedClasses.add(cls);
     } else if (element.impliesType()) {
diff --git a/sdk/lib/_internal/compiler/implementation/js/printer.dart b/sdk/lib/_internal/compiler/implementation/js/printer.dart
index a5870d8..cf61768 100644
--- a/sdk/lib/_internal/compiler/implementation/js/printer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/printer.dart
@@ -1060,7 +1060,7 @@
   }
 
   static const LOWER_CASE_LETTERS = 26;
-  static const LETTERS = 52;
+  static const LETTERS = LOWER_CASE_LETTERS;
   static const DIGITS = 10;
 
   static int nthLetter(int n) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 970af53..c4b8f52 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -1420,15 +1420,14 @@
   bool get rememberLazies => isTreeShakingDisabled;
 
   bool retainMetadataOf(Element element) {
-    if (mustRetainMetadata) {
-      // TODO(ahe): This is a little hacky, but I'll have to rewrite this when
-      // implementing @MirrorsUsed anyways.
-      compiler.constantHandler.compiledConstants.addAll(
-          compiler.metadataHandler.compiledConstants);
-      compiler.metadataHandler.compiledConstants.clear();
-    }
     if (mustRetainMetadata) hasRetainedMetadata = true;
-    return mustRetainMetadata;
+    if (mustRetainMetadata && isNeededForReflection(element)) {
+      for (MetadataAnnotation metadata in element.metadata) {
+        metadata.value.accept(new ConstantCopier(compiler.constantHandler));
+      }
+      return true;
+    }
+    return false;
   }
 
   void onLibraryScanned(LibraryElement library, Uri uri) {
@@ -1509,10 +1508,22 @@
     }
 
     if (!targetsUsed.isEmpty) {
-      for (Element e = element; e != null; e = e.enclosingElement) {
-        if (targetsUsed.contains(e)) return registerNameOf(element);
+      if (targetsUsed.contains(element)) return registerNameOf(element);
+      Element enclosing = element.enclosingElement;
+      if (enclosing != null && isNeededForReflection(enclosing)) {
+        return registerNameOf(element);
       }
     }
+
+    if (element is ClosureClassElement) {
+      // TODO(ahe): Try to fix the enclosing element of ClosureClassElement
+      // instead.
+      ClosureClassElement closureClass = element;
+      if (isNeededForReflection(closureClass.methodElement)) {
+        return registerNameOf(element);
+      }
+    }
+
     return false;
   }
 }
@@ -1524,3 +1535,52 @@
 
   const Dependency(this.type, this.user);
 }
+
+/// Used to copy metadata to the the actual constant handler.
+class ConstantCopier implements ConstantVisitor {
+  final ConstantHandler target;
+
+  ConstantCopier(this.target);
+
+  void copy(/* Constant or List<Constant> */ value) {
+    if (value is Constant) {
+      target.compiledConstants.add(value);
+    } else {
+      target.compiledConstants.addAll(value);
+    }
+  }
+
+  void visitFunction(FunctionConstant constant) => copy(constant);
+
+  void visitNull(NullConstant constant) => copy(constant);
+
+  void visitInt(IntConstant constant) => copy(constant);
+
+  void visitDouble(DoubleConstant constant) => copy(constant);
+
+  void visitTrue(TrueConstant constant) => copy(constant);
+
+  void visitFalse(FalseConstant constant) => copy(constant);
+
+  void visitString(StringConstant constant) => copy(constant);
+
+  void visitType(TypeConstant constant) => copy(constant);
+
+  void visitInterceptor(InterceptorConstant constant) => copy(constant);
+
+  void visitList(ListConstant constant) {
+    copy(constant.entries);
+    copy(constant);
+  }
+  void visitMap(MapConstant constant) {
+    copy(constant.keys);
+    copy(constant.values);
+    copy(constant.protoValue);
+    copy(constant);
+  }
+
+  void visitConstructed(ConstructedConstant constant) {
+    copy(constant.fields);
+    copy(constant);
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
index ace154a..f1b83d9 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -122,7 +122,7 @@
   jsAst.Expression emitCanonicalVersion(Constant constant) {
     String name = namer.constantName(constant);
     return new jsAst.PropertyAccess.field(
-        new jsAst.VariableUse(namer.CURRENT_ISOLATE), name);
+        new jsAst.VariableUse(namer.globalObjectForConstant(constant)), name);
   }
 
   jsAst.Expression visitList(ListConstant constant) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index 21e7b5c..32d3ab8 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -857,11 +857,7 @@
     return js.fun('oldIsolate', [
       js('var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'),
 
-      js(r'isolateProperties.$currentScript ='
-              'typeof document == "object" ?'
-              '(document.currentScript ||'
-                     'document.scripts[document.scripts.length - 1]) :'
-              'null'),
+      js(r'isolateProperties.$currentScript = null'),
 
       js('var isolatePrototype = oldIsolate.prototype'),
       js('var str = "{\\n"'),
@@ -879,6 +875,10 @@
 
       js('str += "}\\n"'),
 
+      js('var Constants = #', js.fun('', [])),
+      // Install 'C' as a prototype to ensure it has a hidden class.
+      js('Constants.prototype = ${namer.globalObjectForConstant(null)}'),
+
       js('var newIsolate = new Function(str)'),
       js('newIsolate.prototype = isolatePrototype'),
       js('isolatePrototype.constructor = newIsolate'),
@@ -1367,6 +1367,10 @@
     Element element = elementOrSelector;
     if (element.isGenerativeConstructorBody()) {
       return null;
+    } else if (element.isClass()) {
+      ClassElement cls = element;
+      if (cls.isUnnamedMixinApplication) return null;
+      return cls.name.slowToString();
     }
     throw compiler.internalErrorOnElement(
         element, 'Do not know how to reflect on this $element');
@@ -1977,8 +1981,8 @@
     buffer.write('$className:$_');
     buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler));
     if (backend.shouldRetainName(classElement.name)) {
-      buffer.write(',$n$n"+${classElement.name.slowToString()}": 0');
-      recordedMangledNames.add(className);
+      String reflectionName = getReflectionName(classElement, className);
+      buffer.write(',$n$n"+$reflectionName": 0');
     }
   }
 
@@ -2683,6 +2687,7 @@
     List<Constant> constants = handler.getConstantsForEmission(
         compareConstants);
     bool addedMakeConstantList = false;
+    eagerBuffer.write('var ${namer.globalObjectForConstant(null)}$_=$_{}$N');
     for (Constant constant in constants) {
       if (isConstantInlinedOrAlreadyEmitted(constant)) continue;
       String name = namer.constantName(constant);
@@ -2691,7 +2696,8 @@
         emitMakeConstantList(eagerBuffer);
       }
       CodeBuffer buffer = bufferForConstant(constant, eagerBuffer);
-      jsAst.Expression init = js('$isolateProperties.$name = #',
+      jsAst.Expression init = js(
+          '${namer.globalObjectForConstant(constant)}.$name = #',
           constantInitializerExpression(constant));
       buffer.write(jsAst.prettyPrint(init, compiler));
       buffer.write('$N');
@@ -2962,24 +2968,47 @@
       buffer.write(N);
     }
     addComment('BEGIN invoke [main].', buffer);
+    // This code finds the currently executing script by listening to the
+    // onload event of all script tags and getting the first script which
+    // finishes. Since onload is called immediately after execution this should
+    // not substantially change execution order.
     buffer.write("""
-if (typeof document !== "undefined" && document.readyState !== "complete") {
-  document.addEventListener("readystatechange", function () {
-    if (document.readyState == "complete") {
-      if (typeof dartMainRunner === "function") {
-        dartMainRunner(function() { ${mainCall}; });
-      } else {
-        ${mainCall};
-      }
+;(function (callback) {
+  if (typeof document === 'undefined') {
+    callback(null);
+    return;
+  }
+  if (document.currentScript) {
+    callback(document.currentScript);
+    return;
+  }
+
+  var scripts = document.scripts;
+  function onLoad() {
+    for (var i = 0; i < scripts.length; ++i) {
+      scripts[i].removeEventListener('load', onLoad, false);
     }
-  }, false);
-} else {
+    callback(event.target);
+  }
+  for (var i = 0; i < scripts.length; ++i) {
+    scripts[i].addEventListener('load', onLoad, false);
+  }
+})(function(currentScript) {
+  ${namer.isolateName}.${namer.isolatePropertiesName}.\$currentScript =
+      currentScript;
+
+  if (typeof console !== 'undefined' && typeof document !== 'undefined' &&
+      document.readyState == "loading") {
+    console.warn("Dart script executed synchronously, use <script src='" +
+        currentScript.src + "' defer></scr" + "ipt> to execute after parsing " +
+        "has completed. See also http://dartbug.com/12281.");
+  }
   if (typeof dartMainRunner === "function") {
     dartMainRunner(function() { ${mainCall}; });
   } else {
     ${mainCall};
   }
-}
+});
 """);
     addComment('END invoke [main].', buffer);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
index 2809dd7..64d0cda 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
@@ -64,7 +64,9 @@
                  bool needsCheckedSetter) {
       fields.add(name);
     });
-    String constructorName = namer.safeName(classElement.name.slowToString());
+    String constructorName =
+        // TODO(ahe): Shouldn't this just be 'namer.getName(classElement)'?
+        namer.safeName(classElement.name.slowToString().replaceAll('+', '_'));
     if (classElement.isNative()) {
       builder.addProperty('', buildUnusedConstructor(constructorName));
     } else {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index 796718a..7d14262 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -145,7 +145,10 @@
     // These keywords trigger the loading of the java-plugin. For the
     // next-generation plugin, this results in starting a new Java process.
     "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass",
-    "JavaArray", "JavaMember"
+    "JavaArray", "JavaMember",
+
+    // Global object for constants.
+    "C",
   ];
 
   Set<String> _jsReserved = null;
@@ -541,7 +544,7 @@
         name = "${enclosingClass.name.slowToString()}_"
                "${element.name.slowToString()}";
       } else {
-        name = element.name.slowToString();
+        name = element.name.slowToString().replaceAll('+', '_');
       }
     } else if (element.isLibrary()) {
       name = LIBRARY_PREFIX;
@@ -775,6 +778,8 @@
     return "$CURRENT_ISOLATE.${getStaticClosureName(element)}";
   }
 
+  String globalObjectForConstant(Constant constant) => 'C';
+
   String operatorIsPrefix() => r'$is';
 
   String operatorAsPrefix() => r'$as';
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index f6f8cc9..f21f244 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -3347,7 +3347,7 @@
     String superName = supertype.name.slowToString();
     String mixinName = mixinType.name.slowToString();
     ClassElement mixinApplication = new MixinApplicationElementX(
-        new SourceString("${superName}_${mixinName}"),
+        new SourceString("${superName}+${mixinName}"),
         element.getCompilationUnit(),
         compiler.getNextFreeClassId(),
         node,
diff --git a/sdk/lib/_internal/compiler/implementation/resolved_visitor.dart b/sdk/lib/_internal/compiler/implementation/resolved_visitor.dart
index 3bfadb2..9a85b9a 100644
--- a/sdk/lib/_internal/compiler/implementation/resolved_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolved_visitor.dart
@@ -10,22 +10,23 @@
   ResolvedVisitor(this.elements);
 
   R visitSend(Send node) {
+    Element element = elements[node];
     if (node.isSuperCall) {
       return visitSuperSend(node);
     } else if (node.isOperator) {
       return visitOperatorSend(node);
     } else if (node.isPropertyAccess) {
-      Element element = elements[node];
       if (!Elements.isUnresolved(element) && element.impliesType()) {
         // A reference to a class literal, typedef or type variable.
         return visitTypeReferenceSend(node);
       } else {
         return visitGetterSend(node);
       }
-    } else if (Elements.isClosureSend(node, elements[node])) {
+    } else if (element != null && Initializers.isConstructorRedirect(node)) {
+      return visitStaticSend(node);
+    } else if (Elements.isClosureSend(node, element)) {
       return visitClosureSend(node);
     } else {
-      Element element = elements[node];
       if (Elements.isUnresolved(element)) {
         if (element == null) {
           // Example: f() with 'f' unbound.
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 7266529..acf5cb9 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -4670,16 +4670,14 @@
 
     // TODO(ngeoffray): Handle switch-instruction in bailout code.
     work.allowSpeculativeOptimization = false;
-    // Then build a switch structure.
     HBasicBlock expressionStart = openNewBlock();
     HInstruction expression = buildExpression();
     if (switchCases.isEmpty) {
       return;
     }
-    HBasicBlock expressionEnd = current;
 
     HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
-    HBasicBlock expressionBlock = close(switchInstruction);
+    HBasicBlock expressionEnd = close(switchInstruction);
     LocalsHandler savedLocals = localsHandler;
 
     List<List<Constant>> matchExpressions = <List<Constant>>[];
@@ -4697,23 +4695,30 @@
         HConstant hConstant = graph.addConstant(constant, compiler);
         switchInstruction.inputs.add(hConstant);
         hConstant.usedBy.add(switchInstruction);
-        expressionBlock.addSuccessor(block);
+        expressionEnd.addSuccessor(block);
       }
       matchExpressions.add(caseConstants);
 
       if (isDefaultCase(switchCase)) {
         // An HSwitch has n inputs and n+1 successors, the last being the
         // default case.
-        expressionBlock.addSuccessor(block);
+        expressionEnd.addSuccessor(block);
         hasDefault = true;
       }
       open(block);
       localsHandler = new LocalsHandler.from(savedLocals);
       buildSwitchCase(switchCase);
-      if (!isAborted() && caseIterator.hasNext) {
-        pushInvokeStatic(switchCase, getFallThroughErrorElement, []);
-        HInstruction error = pop();
-        closeAndGotoExit(new HThrow(error));
+      if (!isAborted()) {
+        if (caseIterator.hasNext) {
+          pushInvokeStatic(switchCase, getFallThroughErrorElement, []);
+          HInstruction error = pop();
+          closeAndGotoExit(new HThrow(error));
+        } else if (!isDefaultCase(switchCase)) {
+          // If there is no default, we will add one later to avoid
+          // the critical edge. So we generate a break statement to make
+          // sure the last case does not fall through to the default case.
+          jumpHandler.generateBreak();
+        }
       }
       statements.add(
           new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock)));
@@ -4742,11 +4747,17 @@
       caseHandlers.add(localsHandler);
     }
     if (!hasDefault) {
-      // The current flow is only aborted if the switch has a default that
-      // aborts (all previous cases must abort, and if there is no default,
-      // it's possible to miss all the cases).
-      expressionEnd.addSuccessor(joinBlock);
+      // Always create a default case, to avoid a critical edge in the
+      // graph.
+      HBasicBlock defaultCase = addNewBlock();
+      expressionEnd.addSuccessor(defaultCase);
+      open(defaultCase);
+      close(new HGoto());
+      defaultCase.addSuccessor(joinBlock);
       caseHandlers.add(savedLocals);
+      matchExpressions.add(<Constant>[]);
+      statements.add(new HSubGraphBlockInformation(new SubGraph(
+          defaultCase, defaultCase)));
     }
     assert(caseHandlers.length == joinBlock.predecessors.length);
     if (caseHandlers.length != 0) {
@@ -4769,7 +4780,6 @@
         new HSwitchBlockInformation(expressionInfo,
                                     matchExpressions,
                                     statements,
-                                    hasDefault,
                                     jumpHandler.target,
                                     jumpHandler.labels()),
         joinBlock);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 3e072dc..f9d8e6a 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -700,7 +700,7 @@
         currentContainer = new js.Block.empty();
         cases.add(new js.Case(pop(), currentContainer));
       }
-      if (i == info.matchExpressions.length - 1 && info.hasDefault) {
+      if (i == info.matchExpressions.length - 1) {
         currentContainer = new js.Block.empty();
         cases.add(new js.Default(currentContainer));
       }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index a580f24..a5110bb 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -2695,16 +2695,12 @@
   final HExpressionInformation expression;
   final List<List<Constant>> matchExpressions;
   final List<HStatementInformation> statements;
-  // If the switch has a default, it's the last statement block, which
-  // may or may not have other expresions.
-  final bool hasDefault;
   final TargetElement target;
   final List<LabelElement> labels;
 
   HSwitchBlockInformation(this.expression,
                           this.matchExpressions,
                           this.statements,
-                          this.hasDefault,
                           this.target,
                           this.labels);
 
diff --git a/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
index 11bd7ac..ab3f998 100644
--- a/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
@@ -320,9 +320,7 @@
   bool couldBeTheList(resolved) {
     if (resolved is Selector) {
       return escapingElements.any((e) {
-        return e.isInstanceMember()
-            && (e.isField() || e.isFunction())
-            && resolved.applies(e, compiler);
+        return e.isInstanceMember() && resolved.applies(e, compiler);
       });
     } else if (resolved is Node) {
       return analyzedNode == resolved;
diff --git a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
index 747f072..ce86ef6 100644
--- a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
@@ -224,14 +224,23 @@
     variables.forEach(f);
   }
 
-  void forEachLocalUntil(Node node, void f(Element, T type)) {
-    forEachOwnLocal(f);
+  void forEachLocalUntilNode(Node node,
+                             void f(Element element, T type),
+                             [Set<Element> seenLocals]) {
+    if (seenLocals == null) seenLocals = new Set<Element>();
+    if (variables != null) {
+      variables.forEach((element, type) {
+        if (seenLocals.contains(element)) return;
+        seenLocals.add(element);
+        f(element, type);
+      });
+    }
     if (block == node) return;
-    if (parent != null) parent.forEachLocalUntil(node, f);
+    if (parent != null) parent.forEachLocalUntilNode(node, f, seenLocals);
   }
 
   void forEachLocal(void f(Element, T type)) {
-    forEachLocalUntil(null, f);
+    forEachLocalUntilNode(null, f);
   }
 
   void remove(Element element) {
@@ -410,13 +419,31 @@
   /**
    * Merge all [LocalsHandler] in [handlers] into [:this:]. Returns
    * whether a local in [:this:] has changed.
+   *
+   * If [keepOwnLocals] is true, the types of locals in this
+   * [LocalsHandler] are being used in the merge. [keepOwnLocals]
+   * should be true if this [LocalsHandler], the dominator of
+   * all [handlers], also direclty flows into the join point,
+   * that is the code after all [handlers]. For example, consider:
+   *
+   * [: switch (...) {
+   *      case 1: ...; break;
+   *    }
+   * :]
+   *
+   * The [LocalsHandler] at entry of the switch also flows into the
+   * exit of the switch, because there is no default case. So the
+   * types of locals at entry of the switch have to take part to the
+   * merge.
    */
-  bool mergeAll(List<LocalsHandler<T>> handlers) {
+  bool mergeAll(List<LocalsHandler<T>> handlers,
+                {bool keepOwnLocals: true}) {
     bool changed = false;
-    handlers.forEach((LocalsHandler<T> handler) {
-      if (handler.seenReturnOrThrow) return;
-      Node level = locals.block;
-      handler.locals.forEachLocalUntil(level, (Element local, T otherType) {
+    Node level = locals.block;
+
+    void mergeHandler(LocalsHandler<T> other) {
+      if (other.seenReturnOrThrow) return;
+      other.locals.forEachLocalUntilNode(level, (local, otherType) {
         T myType = locals[local];
         if (myType == null) return;
         T newType = types.addPhiInput(local, myType, otherType);
@@ -425,7 +452,40 @@
           locals[local] = newType;
         }
       });
-    });
+    }
+
+    if (keepOwnLocals && !seenReturnOrThrow) {
+      handlers.forEach(mergeHandler);
+    } else {
+      // Find the first handler that does not abort.
+      int index = 0;
+      LocalsHandler<T> startWith;
+      while (index < handlers.length
+             && (startWith = handlers[index]).seenReturnOrThrow) {
+        index++;
+      }
+      if (index == handlers.length) {
+        // If we haven't found a handler that does not abort, we know
+        // this handler aborts.
+        seenReturnOrThrow = true;
+      } else {
+        // Otherwise, this handler does not abort.
+        seenReturnOrThrow = false;
+        // Use [startWith] to initialize the types of locals.
+        startWith.locals.forEachLocalUntilNode(level, (local, otherType) {
+          T myType = locals[local];
+          if (myType == null) return;
+          if (myType != otherType) {
+            changed = true;
+            locals[local] = otherType;
+          }
+        });
+        // Merge all other handlers.
+        for (int i = index + 1; i < handlers.length; i++) {
+          mergeHandler(handlers[i]);
+        }
+      }
+    }
     return changed;
   }
 
@@ -462,6 +522,7 @@
   final Map<TargetElement, List<LocalsHandler>> continuesFor =
       new Map<TargetElement, List<LocalsHandler<T>>>();
   LocalsHandler<T> locals;
+  final List<T> cascadeReceiverStack = new List<T>();
 
   bool accumulateIsChecks = false;
   bool conditionIsSimple = false;
@@ -795,14 +856,22 @@
     loopLevel++;
     bool changed = false;
     TargetElement target = elements[node];
-    setupBreaksAndContinues(target);
     locals.startLoop(node);
     LocalsHandler<T> saved;
+    bool keepOwnLocals = node.asDoWhile() == null;
     do {
+      // Setup (and clear in case of multiple iterations of the loop)
+      // the lists of breaks and continues seen in the loop.
+      setupBreaksAndContinues(target);
       saved = locals;
       locals = new LocalsHandler<T>.from(locals, node);
       logic();
-      changed = saved.mergeAll(getLoopBackEdges(target));
+      changed = saved.mergeAll(getLoopBackEdges(target),
+                               keepOwnLocals: keepOwnLocals);
+      // Now that we have done the initial merge, following merges to
+      // reach a fixed point must use the previously computed types of
+      // locals at entry of the loop.
+      keepOwnLocals = true;
       locals = saved;
     } while (changed);
     loopLevel--;
@@ -973,36 +1042,32 @@
     } else {
       LocalsHandler<T> saved = locals;
       List<LocalsHandler<T>> localsToMerge = <LocalsHandler<T>>[];
+      bool hasDefaultCase = false;
 
       for (SwitchCase switchCase in node.cases) {
+        if (switchCase.isDefaultCase) {
+          hasDefaultCase = true;
+        }
         locals = new LocalsHandler<T>.from(saved, switchCase);
         visit(switchCase);
         localsToMerge.add(locals);
       }
-      saved.mergeAll(localsToMerge);
+      saved.mergeAll(localsToMerge, keepOwnLocals: !hasDefaultCase);
       locals = saved;
     }
     clearBreaksAndContinues(elements[node]);
-    // In case there is a default in the switch we discard the
-    // incoming localsHandler, because the types it holds do not need
-    // to be merged after the switch statement. This means that, if all
-    // cases, including the default, break or continue, the [result]
-    // handler may think it just aborts the current block. Therefore
-    // we set the current locals to not have any break or continue, so
-    // that the [visitBlock] method does not assume the code after the
-    // switch is dead code.
-    locals.seenBreakOrContinue = false;
   }
 
   T visitCascadeReceiver(CascadeReceiver node) {
-    // TODO(ngeoffray): Implement.
-    node.visitChildren(this);
-    return types.dynamicType;
+    var type = visit(node.expression);
+    cascadeReceiverStack.add(type);
+    return type;
   }
 
   T visitCascade(Cascade node) {
-    // TODO(ngeoffray): Implement.
-    node.visitChildren(this);
-    return types.dynamicType;
+    // Ignore the result of the cascade send and return the type of the cascade
+    // receiver.
+    visit(node.expression);
+    return cascadeReceiverStack.removeLast();
   }
 }
diff --git a/sdk/lib/_internal/lib/core_patch.dart b/sdk/lib/_internal/lib/core_patch.dart
index b256d0f..207800a 100644
--- a/sdk/lib/_internal/lib/core_patch.dart
+++ b/sdk/lib/_internal/lib/core_patch.dart
@@ -115,11 +115,9 @@
     return Primitives.objectToString(object);
   }
 
-  // TODO(11681): implement stackTrace in error object.
-  patch StackTrace get stackTrace => null;
+  patch StackTrace get stackTrace => Primitives.extractStackTrace(this);
 }
 
-
 // Patch for DateTime implementation.
 patch class DateTime {
   patch DateTime._internal(int year,
diff --git a/sdk/lib/_internal/lib/foreign_helper.dart b/sdk/lib/_internal/lib/foreign_helper.dart
index 7268ead..73e3c09 100644
--- a/sdk/lib/_internal/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/lib/foreign_helper.dart
@@ -38,8 +38,9 @@
  *     that have no corresponing Dart type (e.g. cross-frame documents),
  *     `=Object` can be used to describe these untyped' values.
  *
- *  + `var`.  If the entire [typeDescription] is `var` then the type is
- *    `dynamic` but the code is known to not create any instances.
+ *  + `var` (or empty string).  If the entire [typeDescription] is `var` (or
+ *    empty string) then the type is `dynamic` but the code is known to not
+ *    create any instances.
  *
  * Examples:
  *
diff --git a/sdk/lib/_internal/lib/interceptors.dart b/sdk/lib/_internal/lib/interceptors.dart
index 5e6e77e..27c2edf 100644
--- a/sdk/lib/_internal/lib/interceptors.dart
+++ b/sdk/lib/_internal/lib/interceptors.dart
@@ -51,9 +51,10 @@
   // This is a magic method: the compiler does specialization of it
   // depending on the uses of intercepted methods and instantiated
   // primitive types.
-  // This method is recursive to prevent the type analyzer from thinking that
-  // the method returns `null`.
-  return getInterceptor(object);
+
+  // The [JS] call prevents the type analyzer from making assumptions about the
+  // return type.
+  return JS('', 'void 0');
 }
 
 /**
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index 5725d1e..6aed3a2 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -210,6 +210,18 @@
        Encoding stderrEncoding: Encoding.SYSTEM}) {
     throw new UnsupportedError("Process.run");
   }
+
+  patch static ProcessResult runSync(
+      String executable,
+      List<String> arguments,
+      {String workingDirectory,
+       Map<String, String> environment,
+       bool includeParentEnvironment: true,
+       bool runInShell: false,
+       Encoding stdoutEncoding: Encoding.SYSTEM,
+       Encoding stderrEncoding: Encoding.SYSTEM}) {
+    throw new UnsupportedError("Process.runSync");
+  }
 }
 
 patch class InternetAddress {
@@ -277,7 +289,8 @@
 
   patch static void initialize({String database,
                                 String password,
-                                bool useBuiltinRoots: true}) {
+                                bool useBuiltinRoots: true,
+                                bool readOnly: true}) {
     throw new UnsupportedError("SecureSocket.initialize");
   }
 
@@ -285,6 +298,24 @@
                                               String trust) {
     throw new UnsupportedError("SecureSocket.addCertificate");
   }
+
+  patch static importCertificatesWithPrivateKeys(List<int> certificates,
+                                                 String password) {
+    throw new UnsupportedError(
+        "SecureSocket.importCertificatesWithPrivateKeys");
+  }
+
+  patch static X509Certificate getCertificate(String nickname) {
+    throw new UnsupportedError("SecureSocket.getCertificate");
+  }
+
+  patch static removeCertificate(String nickname) {
+    throw new UnsupportedError("SecureSocket.removeCertificate");
+  }
+
+  patch static X509Certificate changeTrust(String nickname, String trust) {
+    throw new UnsupportedError("SecureSocket.changeTrust");
+  }
 }
 
 patch class _SecureFilter {
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
index 2a25f54..d59dbb8 100644
--- a/sdk/lib/_internal/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/lib/isolate_helper.dart
@@ -7,8 +7,10 @@
 import 'dart:async';
 import 'dart:collection' show Queue, HashMap;
 import 'dart:isolate';
-import 'dart:_js_helper' show convertDartClosureToJS,
-                              Null;
+import 'dart:_js_helper' show
+    Null,
+    Primitives,
+    convertDartClosureToJS;
 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
                                    JS,
                                    JS_CREATE_ISOLATE,
@@ -643,6 +645,8 @@
   }
 
   static void _startIsolate(Function topLevel, SendPort replyTo) {
+    _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT();
+    Primitives.initializeStatics(context.id);
     lazyPort = new ReceivePort();
     replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
     topLevel();
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index 0efd6c2..ab69f61 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -29,7 +29,7 @@
                                    RAW_DART_FUNCTION_REF;
 import 'dart:_interceptors';
 import 'dart:_collection-dev' as _symbol_dev;
-import 'dart:_js_names' show mangledNames;
+import 'dart:_js_names' show mangledNames, mangledGlobalNames;
 
 part 'constant_map.dart';
 part 'native_helper.dart';
@@ -142,7 +142,7 @@
     return map;
   }
 
-  _invokeOn(Object object) {
+  _getCachedInvocation(Object object) {
     var interceptor = getInterceptor(object);
     var receiver = object;
     var name = _internalName;
@@ -151,30 +151,107 @@
     // critical, we might want to dynamically change [interceptedNames]
     // to be a JavaScript object with intercepted names as property
     // instead of a JavaScript array.
-    if (JS('int', '#.indexOf(#)', interceptedNames, name) == -1) {
-      if (arguments is! JSArray) arguments = new List.from(arguments);
-    } else {
-      arguments = [object]..addAll(arguments);
+    bool isIntercepted =
+        JS('int', '#.indexOf(#)', interceptedNames, name) != -1;
+    if (isIntercepted) {
       receiver = interceptor;
+      if (JS('bool', '# === #', object, interceptor)) {
+        interceptor = null;
+      }
+    } else {
+      interceptor = null;
     }
     var method = JS('var', '#[#]', receiver, name);
     if (JS('String', 'typeof #', method) == 'function') {
-      return JS("var", "#.apply(#, #)", method, receiver, arguments);
+      return new CachedInvocation(method, isIntercepted, interceptor);
     } else {
       // In this case, receiver doesn't implement name.  So we should
       // invoke noSuchMethod instead (which will often throw a
       // NoSuchMethodError).
-      return receiver.noSuchMethod(this);
+      return new CachedNoSuchMethodInvocation(interceptor);
     }
   }
 
   /// This method is called by [InstanceMirror.delegate].
-  static invokeFromMirror(JSInvocationMirror invocation, victim) {
-    return invocation._invokeOn(victim);
+  static invokeFromMirror(JSInvocationMirror invocation, Object victim) {
+    var cached = invocation._getCachedInvocation(victim);
+    if (cached.isNoSuchMethod) {
+      return cached.invokeOn(victim, invocation);
+    } else {
+      return cached.invokeOn(victim, invocation._arguments);
+    }
+  }
+
+  static getCachedInvocation(JSInvocationMirror invocation, Object victim) {
+    return invocation._getCachedInvocation(victim);
+  }
+}
+
+class CachedInvocation {
+  /// The JS function to call.
+  var jsFunction;
+
+  /// True if this is an intercepted call.
+  bool isIntercepted;
+
+  /// Non-null interceptor if this is an intercepted call through an
+  /// [Interceptor].
+  Interceptor cachedInterceptor;
+
+  CachedInvocation(this.jsFunction, this.isIntercepted, this.cachedInterceptor);
+
+  bool get isNoSuchMethod => false;
+
+  /// Applies [jsFunction] to object with [arguments].
+  /// Users of this class must take care to check the arguments first.
+  invokeOn(Object victim, List arguments) {
+    var receiver = victim;
+    if (!isIntercepted) {
+      if (arguments is! JSArray) arguments = new List.from(arguments);
+    } else {
+      arguments = [victim]..addAll(arguments);
+      if (cachedInterceptor != null) receiver = cachedInterceptor;
+    }
+    return JS("var", "#.apply(#, #)", jsFunction, receiver, arguments);
+  }
+}
+
+class CachedNoSuchMethodInvocation {
+  /// Non-null interceptor if this is an intercepted call through an
+  /// [Interceptor].
+  var interceptor;
+
+  CachedNoSuchMethodInvocation(this.interceptor);
+
+  bool get isNoSuchMethod => true;
+
+  invokeOn(Object victim, Invocation invocation) {
+    var receiver = (interceptor == null) ? victim : interceptor;
+    return receiver.noSuchMethod(invocation);
   }
 }
 
 class Primitives {
+  /// Isolate-unique ID for caching [JsClosureMirror.function].
+  /// Note the initial value is used by the first isolate (or if there are no
+  /// isolates), new isolates will update this value to avoid conflicts by
+  /// calling [initializeStatics].
+  static String mirrorFunctionCacheName = '\$cachedFunction';
+
+  /// Isolate-unique ID for caching [JsInstanceMirror._invoke].
+  static String mirrorInvokeCacheName = '\$cachedInvocation';
+
+  /// Called when creating a new isolate (see _IsolateContext constructor in
+  /// isolate_helper.dart).
+  /// Please don't add complicated code to this method, as it will impact
+  /// start-up performance.
+  static void initializeStatics(int id) {
+    // Benchmarking shows significant performance improvements if this is a
+    // fixed value.
+    mirrorFunctionCacheName += '_$id';
+    mirrorInvokeCacheName += '_$id';
+  }
+
   static int objectHashCode(object) {
     int hash = JS('int|Null', r'#.$identityHash', object);
     if (hash == null) {
@@ -641,6 +718,30 @@
       ? JS('bool', '# == null', b)
       : JS('bool', '# === #', a, b);
   }
+
+  static StackTrace extractStackTrace(Error error) {
+    return getTraceFromException(JS('', r'#.$thrownJsError', error));
+  }
+}
+
+/// Helper class for allocating and using JS object literals as caches.
+class JsCache {
+  /// Returns a JavaScript object suitable for use as a cache.
+  static allocate() {
+    var result = JS('=Object', '{x:0}');
+    // Deleting a property makes V8 assume that it shouldn't create a hidden
+    // class for [result] and map transitions. Although these map transitions
+    // pay off if there are many cache hits for the same keys, it becomes
+    // really slow when there aren't many repeated hits.
+    JS('void', 'delete #.x', result);
+    return result;
+  }
+
+  static fetch(cache, String key) => JS('', '#[#]', cache, key);
+
+  static void update(cache, String key, value) {
+    JS('void', '#[#] = #', cache, key, value);
+  }
 }
 
 /**
@@ -708,23 +809,34 @@
  */
 wrapException(ex) {
   if (ex == null) ex = new NullThrownError();
-  var wrapper = new DartError(ex);
+  var wrapper = JS('', 'new Error()');
+  // [unwrapException] looks for the property 'dartException'.
+  JS('void', '#.dartException = #', wrapper, ex);
 
-  if (JS('bool', '!!Error.captureStackTrace')) {
-    // Use V8 API for recording a "fast" stack trace (this installs a
-    // "stack" property getter on [wrapper]).
-    JS('void', r'Error.captureStackTrace(#, #)',
-       wrapper, RAW_DART_FUNCTION_REF(wrapException));
+  if (JS('bool', '"defineProperty" in Object')) {
+    // Define a JavaScript getter for 'message'. This is to work around V8 bug
+    // (https://code.google.com/p/v8/issues/detail?id=2519).  The default
+    // toString on Error returns the value of 'message' if 'name' is
+    // empty. Setting toString directly doesn't work, see the bug.
+    JS('void', 'Object.defineProperty(#, "message", { get: # })',
+       wrapper, DART_CLOSURE_TO_JS(toStringWrapper));
+    JS('void', '#.name = ""', wrapper);
   } else {
-    // Otherwise, produce a stack trace and record it in the wrapper.
-    // This is a slower way to create a stack trace which works on
-    // some browsers, but may simply evaluate to null.
-    String stackTrace = JS('', 'new Error().stack');
-    JS('void', '#.stack = #', wrapper, stackTrace);
+    // In the unlikely event the browser doesn't support Object.defineProperty,
+    // hope that it just calls toString.
+    JS('void', '#.toString = #', wrapper, DART_CLOSURE_TO_JS(toStringWrapper));
   }
+
   return wrapper;
 }
 
+/// Do not call directly.
+toStringWrapper() {
+  // This method gets installed as toString on a JavaScript object. Due to the
+  // weird scope rules of JavaScript, JS 'this' will refer to that object.
+  return JS('', r'this.dartException').toString();
+}
+
 /**
  * This wraps the exception and does the throw.  It is possible to call this in
  * a JS expression context, where the throw statement is not allowed.  Helpers
@@ -735,63 +847,6 @@
   JS('void', 'throw #', wrapException(ex));
 }
 
-/**
- * Wrapper class for throwing exceptions.
- */
-class DartError {
-  /// The Dart object (or primitive JavaScript value) which was thrown is
-  /// attached to this object as a field named 'dartException'.  We do this
-  /// only in raw JS so that we can use the 'in' operator and so that the
-  /// minifier does not rename the field.  Therefore it is not declared as a
-  /// real field.
-
-  DartError(var dartException) {
-    JS('void', '#.dartException = #', this, dartException);
-    // Install a toString method that the JavaScript system will call
-    // to format uncaught exceptions.
-    JS('void', '#.toString = #', this, DART_CLOSURE_TO_JS(toStringWrapper));
-  }
-
-  /**
-   * V8/Chrome installs a property getter, "stack", when calling
-   * Error.captureStackTrace (see [wrapException]). In [wrapException], we make
-   * sure that this property is always set.
-   */
-  String get stack => JS('', '#.stack', this);
-
-  /**
-   * This method can be invoked by calling toString from
-   * JavaScript. See the constructor of this class.
-   *
-   * We only expect this method to be called (indirectly) by the
-   * browser when an uncaught exception occurs. Instance of this class
-   * should never escape into Dart code (except for [wrapException] above).
-   */
-  String toString() {
-    // If Error.captureStackTrace is available, accessing stack from
-    // this method would cause recursion because the stack property
-    // (on this object) is actually a getter which calls toString on
-    // this object (via the wrapper installed in this class'
-    // constructor). Fortunately, both Chrome and d8 prints the stack
-    // trace and Chrome even applies source maps to the stack
-    // trace. Remeber, this method is only ever invoked by the browser
-    // when an uncaught exception occurs.
-    var dartException = JS('var', r'#.dartException', this);
-    if (JS('bool', '!!Error.captureStackTrace') || (stack == null)) {
-      return dartException.toString();
-    } else {
-      return '$dartException\n$stack';
-    }
-  }
-
-  /**
-   * This method is installed as JavaScript toString method on
-   * [DartError].  So JavaScript 'this' binds to an instance of
-   * DartError.
-   */
-  static toStringWrapper() => JS('', r'this').toString();
-}
-
 makeLiteralListConst(list) {
   JS('bool', r'#.immutable$list = #', list, true);
   JS('bool', r'#.fixed$length = #', list, true);
@@ -1140,7 +1195,7 @@
   }
 }
 
-class NullError implements NoSuchMethodError {
+class NullError extends Error implements NoSuchMethodError {
   final String _message;
   final String _method;
 
@@ -1153,7 +1208,7 @@
   }
 }
 
-class JsNoSuchMethodError implements NoSuchMethodError {
+class JsNoSuchMethodError extends Error implements NoSuchMethodError {
   final String _message;
   final String _method;
   final String _receiver;
@@ -1173,7 +1228,7 @@
   }
 }
 
-class UnknownJsTypeError implements Error {
+class UnknownJsTypeError extends Error {
   final String _message;
 
   UnknownJsTypeError(this._message);
@@ -1190,13 +1245,26 @@
  * returned unmodified.
  */
 unwrapException(ex) {
+  /// If error implements Error, save [ex] in [error.$thrownJsError].
+  /// Otherwise, do nothing. Later, the stack trace can then be extraced from
+  /// [ex].
+  saveStackTrace(error) {
+    if (error is Error) {
+      var thrownStackTrace = JS('', r'#.$thrownJsError', error);
+      if (thrownStackTrace == null) {
+        JS('void', r'#.$thrownJsError = #', error, ex);
+      }
+    }
+    return error;
+  }
+
   // Note that we are checking if the object has the property. If it
   // has, it could be set to null if the thrown value is null.
   if (ex == null) return null;
   if (JS('bool', 'typeof # !== "object"', ex)) return ex;
 
   if (JS('bool', r'"dartException" in #', ex)) {
-    return JS('', r'#.dartException', ex);
+    return saveStackTrace(JS('', r'#.dartException', ex));
   } else if (!JS('bool', r'"message" in #', ex)) {
     return ex;
   }
@@ -1222,10 +1290,12 @@
     if (ieFacilityNumber == 10) {
       switch (ieErrorCode) {
       case 438:
-        return new JsNoSuchMethodError('$message (Error $ieErrorCode)', null);
+        return saveStackTrace(
+            new JsNoSuchMethodError('$message (Error $ieErrorCode)', null));
       case 445:
       case 5007:
-        return new NullError('$message (Error $ieErrorCode)', null);
+        return saveStackTrace(
+            new NullError('$message (Error $ieErrorCode)', null));
       }
     }
   }
@@ -1258,14 +1328,14 @@
         JS('TypeErrorDecoder', '#',
            TypeErrorDecoder.undefinedLiteralPropertyPattern);
     if ((match = nsme.matchTypeError(message)) != null) {
-      return new JsNoSuchMethodError(message, match);
+      return saveStackTrace(new JsNoSuchMethodError(message, match));
     } else if ((match = notClosure.matchTypeError(message)) != null) {
       // notClosure may match "({c:null}).c()" or "({c:1}).c()", so we
       // cannot tell if this an attempt to invoke call on null or a
       // non-function object.
       // But we do know the method name is "call".
       JS('', '#.method = "call"', match);
-      return new JsNoSuchMethodError(message, match);
+      return saveStackTrace(new JsNoSuchMethodError(message, match));
     } else if ((match = nullCall.matchTypeError(message)) != null ||
                (match = nullLiteralCall.matchTypeError(message)) != null ||
                (match = undefCall.matchTypeError(message)) != null ||
@@ -1274,13 +1344,14 @@
                (match = nullLiteralCall.matchTypeError(message)) != null ||
                (match = undefProperty.matchTypeError(message)) != null ||
                (match = undefLiteralProperty.matchTypeError(message)) != null) {
-      return new NullError(message, match);
+      return saveStackTrace(new NullError(message, match));
     }
 
     // If we cannot determine what kind of error this is, we fall back
     // to reporting this as a generic error. It's probably better than
     // nothing.
-    return new UnknownJsTypeError(message is String ? message : '');
+    return saveStackTrace(
+        new UnknownJsTypeError(message is String ? message : ''));
   }
 
   if (JS('bool', r'# instanceof RangeError', ex)) {
@@ -1291,7 +1362,7 @@
     // In general, a RangeError is thrown when trying to pass a number
     // as an argument to a function that does not allow a range that
     // includes that number.
-    return new ArgumentError();
+    return saveStackTrace(new ArgumentError());
   }
 
   // Check for the Firefox specific stack overflow signal.
@@ -1311,24 +1382,25 @@
 
 /**
  * Called by generated code to fetch the stack trace from an
- * exception.
+ * exception. Should never return null.
  */
-StackTrace getTraceFromException(exception) {
-  if (exception == null) return null;
-  if (JS('bool', 'typeof # !== "object"', exception)) return null;
-  if (JS('bool', r'"stack" in #', exception)) {
-    return new _StackTrace(JS("var", r"#.stack", exception));
-  } else {
-    return null;
-  }
-}
+StackTrace getTraceFromException(exception) => new _StackTrace(exception);
 
 class _StackTrace implements StackTrace {
-  var _stack;
-  _StackTrace(this._stack);
-  String toString() => _stack != null ? _stack : '';
-}
+  var _exception;
+  String _trace;
+  _StackTrace(this._exception);
 
+  String toString() {
+    if (_trace != null) return _trace;
+
+    String trace;
+    if (JS('bool', 'typeof # === "object"', _exception)) {
+      trace = JS("String|Null", r"#.stack", _exception);
+    }
+    return _trace = (trace == null) ? '' : trace;
+  }
+}
 
 /**
  * Called by generated code to build a map literal. [keyValuePairs] is
@@ -1805,7 +1877,7 @@
 // When they are, remove the 'Implementation' here.
 
 /** Thrown by type assertions that fail. */
-class TypeErrorImplementation implements TypeError {
+class TypeErrorImplementation extends Error implements TypeError {
   final String message;
 
   /**
@@ -1819,7 +1891,7 @@
 }
 
 /** Thrown by the 'as' operator if the cast isn't valid. */
-class CastErrorImplementation implements CastError {
+class CastErrorImplementation extends Error implements CastError {
   // TODO(lrn): Rename to CastError (and move implementation into core).
   final String message;
 
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index 7beac1b..3914b20 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -5,6 +5,7 @@
 library dart._js_mirrors;
 
 import 'dart:async';
+import 'dart:collection' show UnmodifiableListView;
 import 'dart:mirrors';
 
 import 'dart:_foreign_helper' show
@@ -17,13 +18,16 @@
     BoundClosure,
     Closure,
     JSInvocationMirror,
+    JsCache,
     Null,
     Primitives,
     RuntimeError,
     createRuntimeType,
     createUnmangledInvocationMirror,
     runtimeTypeToString;
-import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+import 'dart:_interceptors' show
+    Interceptor,
+    JSExtendableArray;
 import 'dart:_js_names';
 
 /// No-op method that is called to inform the compiler that tree-shaking needs
@@ -40,6 +44,8 @@
 }
 
 class JsMirrorSystem implements MirrorSystem {
+  UnmodifiableMapView<Uri, LibraryMirror> _cachedLibraries;
+
   final IsolateMirror isolate = new JsIsolateMirror();
 
   TypeMirror get dynamicType => _dynamicType;
@@ -53,17 +59,20 @@
       computeLibrariesByName();
 
   Map<Uri, LibraryMirror> get libraries {
-    Map<Uri, LibraryMirror> result = new Map<Uri, LibraryMirror>();
+    if (_cachedLibraries != null) return _cachedLibraries;
+    Map<Uri, LibraryMirror> result = new Map();
     for (List<LibraryMirror> list in librariesByName.values) {
       for (LibraryMirror library in list) {
         result[library.uri] = library;
       }
     }
-    return result;
+    return _cachedLibraries =
+        new UnmodifiableMapView<Uri, LibraryMirror>(result);
   }
 
   Iterable<LibraryMirror> findLibrary(Symbol libraryName) {
-    return new List<LibraryMirror>.from(librariesByName[n(libraryName)]);
+    return new UnmodifiableListView<LibraryMirror>(
+        librariesByName[n(libraryName)]);
   }
 
   static Map<String, List<LibraryMirror>> computeLibrariesByName() {
@@ -149,6 +158,7 @@
 
   bool get isTopLevel => owner != null && owner is LibraryMirror;
 
+  // TODO(ahe): This should use qualifiedName.
   String toString() => "$_prettyName on '${n(simpleName)}'";
 
   List<JsMethodMirror> get _methods {
@@ -188,6 +198,13 @@
   final bool _isRoot;
   List<JsMethodMirror> _cachedFunctionMirrors;
   List<JsVariableMirror> _cachedFields;
+  UnmodifiableMapView<Symbol, ClassMirror> _cachedClasses;
+  UnmodifiableMapView<Symbol, MethodMirror> _cachedFunctions;
+  UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters;
+  UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters;
+  UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables;
+  UnmodifiableMapView<Symbol, Mirror> _cachedMembers;
+  UnmodifiableListView<InstanceMirror> _cachedMetadata;
 
   JsLibraryMirror(Symbol simpleName,
                   this.uri,
@@ -205,13 +222,17 @@
   List<JsMethodMirror> get _methods => _functionMirrors;
 
   Map<Symbol, ClassMirror> get classes {
-    var result = new Map<Symbol, ClassMirror>();
+    if (_cachedClasses != null) return _cachedClasses;
+    var result = new Map();
     for (String className in _classes) {
-      JsClassMirror cls = reflectClassByMangledName(className);
-      result[cls.simpleName] = cls;
-      cls._owner = this;
+      var cls = reflectClassByMangledName(className);
+      if (cls is JsClassMirror) {
+        result[cls.simpleName] = cls;
+        cls._owner = this;
+      }
     }
-    return result;
+    return _cachedClasses =
+        new UnmodifiableMapView<Symbol, ClassMirror>(result);
   }
 
   InstanceMirror setField(Symbol fieldName, Object arg) {
@@ -293,40 +314,48 @@
     var result = <VariableMirror>[];
     parseCompactFieldSpecification(
         this, _compactFieldSpecification, true, result);
-    _cachedFields = result;
-    return _cachedFields;
+    return _cachedFields = result;
   }
 
   Map<Symbol, MethodMirror> get functions {
-    var result = new Map<Symbol, MethodMirror>();
+    if (_cachedFunctions != null) return _cachedFunctions;
+    var result = new Map();
     for (JsMethodMirror mirror in _functionMirrors) {
       if (!mirror.isConstructor) result[mirror.simpleName] = mirror;
     }
-    return result;
+    return _cachedFunctions =
+        new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
   Map<Symbol, MethodMirror> get getters {
-    var result = new Map<Symbol, MethodMirror>();
+    if (_cachedGetters != null) return _cachedGetters;
+    var result = new Map();
     // TODO(ahe): Implement this.
-    return result;
+    return _cachedGetters =
+        new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
   Map<Symbol, MethodMirror> get setters {
-    var result = new Map<Symbol, MethodMirror>();
+    if (_cachedSetters != null) return _cachedSetters;
+    var result = new Map();
     // TODO(ahe): Implement this.
-    return result;
+    return _cachedSetters =
+        new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
   Map<Symbol, VariableMirror> get variables {
-    var result = new Map<Symbol, VariableMirror>();
+    if (_cachedVariables != null) return _cachedVariables;
+    var result = new Map();
     for (JsVariableMirror mirror in _fields) {
       result[mirror.simpleName] = mirror;
     }
-    return result;
+    return _cachedVariables =
+        new UnmodifiableMapView<Symbol, VariableMirror>(result);
   }
 
   Map<Symbol, Mirror> get members {
-    Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(classes);
+    if (_cachedMembers !=  null) return _cachedMembers;
+    Map<Symbol, Mirror> result = new Map.from(classes);
     addToResult(Symbol key, Mirror value) {
       result[key] = value;
     }
@@ -334,12 +363,14 @@
     getters.forEach(addToResult);
     setters.forEach(addToResult);
     variables.forEach(addToResult);
-    return result;
+    return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(result);
   }
 
   List<InstanceMirror> get metadata {
+    if (_cachedMetadata != null) return _cachedMetadata;
     preserveMetadata();
-    return _metadata.map(reflect).toList();
+    return _cachedMetadata =
+        new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect));
   }
 
   // TODO(ahe): Test this getter.
@@ -363,9 +394,10 @@
   }
 }
 
-final Expando<ClassMirror> classMirrors = new Expando<ClassMirror>();
-
 ClassMirror reflectType(Type key) {
+  // TODO(ahe): Don't discard type arguments to support
+  // [ClassMirror.isOriginalDeclaration] and [ClassMirror.originalDeclaration]
+  // correctly.
   return reflectClassByMangledName('$key'.split('<')[0]);
 }
 
@@ -375,7 +407,12 @@
   return reflectClassByName(s(unmangledName), mangledName);
 }
 
+var classMirrors;
+
 ClassMirror reflectClassByName(Symbol symbol, String mangledName) {
+  if (classMirrors == null) classMirrors = JsCache.allocate();
+  var mirror = JsCache.fetch(classMirrors, mangledName);
+  if (mirror != null) return mirror;
   disableTreeShaking();
   var constructorOrInterceptor =
       Primitives.getConstructorOrInterceptor(mangledName);
@@ -405,15 +442,118 @@
       fields = '';
     }
   }
-  var mirror = classMirrors[constructorOrInterceptor];
-  if (mirror == null) {
+
+  var superclassName = fields.split(';')[0];
+  var mixins = superclassName.split('+');
+  if (mixins.length > 1 && mangledGlobalNames[mangledName] == null) {
+    mirror = reflectMixinApplication(mixins, mangledName);
+  } else {
     mirror = new JsClassMirror(
         symbol, mangledName, constructorOrInterceptor, fields, fieldsMetadata);
-    classMirrors[constructorOrInterceptor] = mirror;
   }
+
+  JsCache.update(classMirrors, mangledName, mirror);
   return mirror;
 }
 
+int counter = 0;
+
+ClassMirror reflectMixinApplication(mixinNames, String mangledName) {
+  disableTreeShaking();
+  var mixins = [];
+  for (String mangledName in mixinNames) {
+    mixins.add(reflectClassByMangledName(mangledName));
+  }
+  var it = mixins.iterator;
+  it.moveNext();
+  var superclass = it.current;
+  while (it.moveNext()) {
+    superclass = new JsMixinApplication(superclass, it.current, mangledName);
+  }
+  return superclass;
+}
+
+class JsMixinApplication extends JsTypeMirror with JsObjectMirror
+    implements ClassMirror {
+  final ClassMirror superclass;
+  final ClassMirror mixin;
+
+  JsMixinApplication(ClassMirror superclass, ClassMirror mixin,
+                     String mangledName)
+      : this.superclass = superclass,
+        this.mixin = mixin,
+        super(s(mangledName));
+
+  String get _prettyName => 'ClassMirror';
+
+  Symbol get simpleName {
+    return s('${n(mixin.qualifiedName)}(${n(superclass.qualifiedName)})');
+  }
+
+  Symbol get qualifiedName => simpleName;
+
+  Map<Symbol, Mirror> get members => mixin.members;
+
+  Map<Symbol, MethodMirror> get methods => mixin.methods;
+
+  Map<Symbol, MethodMirror> get getters => mixin.getters;
+
+  Map<Symbol, MethodMirror> get setters => mixin.setters;
+
+  Map<Symbol, VariableMirror> get variables => mixin.variables;
+
+  InstanceMirror invoke(
+      Symbol memberName,
+      List positionalArguments,
+      [Map<Symbol,dynamic> namedArguments]) {
+    // TODO(ahe): Pass namedArguments when NoSuchMethodError has
+    // been fixed to use Symbol.
+    // TODO(ahe): What receiver to use?
+    throw new NoSuchMethodError(this, n(memberName), positionalArguments, null);
+  }
+
+  InstanceMirror getField(Symbol fieldName) {
+    // TODO(ahe): What receiver to use?
+    throw new NoSuchMethodError(this, n(fieldName), null, null);
+  }
+
+  InstanceMirror setField(Symbol fieldName, Object arg) {
+    // TODO(ahe): What receiver to use?
+    throw new NoSuchMethodError(this, '${n(fieldName)}=', [arg], null);
+  }
+
+  List<ClassMirror> get superinterfaces => mixin.superinterfaces;
+
+  Map<Symbol, MethodMirror> get constructors => mixin.constructors;
+
+  InstanceMirror newInstance(
+      Symbol constructorName,
+      List positionalArguments,
+      [Map<Symbol,dynamic> namedArguments]) {
+    throw new UnsupportedError(
+        "Can't instantiate mixin application '${n(qualifiedName)}'");
+  }
+
+  Future<InstanceMirror> newInstanceAsync(
+      Symbol constructorName,
+      List positionalArguments,
+      [Map<Symbol, dynamic> namedArguments]) {
+    return new Future<InstanceMirror>(
+        () => this.newInstance(
+            constructorName, positionalArguments, namedArguments));
+  }
+
+  bool get isOriginalDeclaration => true;
+
+  ClassMirror get originalDeclaration => this;
+
+  // TODO(ahe): Implement these.
+  Map<Symbol, TypeVariableMirror> get typeVariables {
+    throw new UnimplementedError();
+  }
+  Map<Symbol, TypeMirror> get typeArguments => throw new UnimplementedError();
+}
+
 abstract class JsObjectMirror implements ObjectMirror {
   Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) {
     return new Future<InstanceMirror>(() => this.setField(fieldName, value));
@@ -457,38 +597,67 @@
     if (namedArguments != null && !namedArguments.isEmpty) {
       throw new UnsupportedError('Named arguments are not implemented.');
     }
-    // Copy the list to ensure that it can safely be passed to
-    // JavaScript.
-    var jsList = new List.from(positionalArguments);
-    String reflectiveName = '${n(memberName)}:${positionalArguments.length}:0';
-    String mangledName = reflectiveNames[reflectiveName];
-    return _invoke(memberName, JSInvocationMirror.METHOD, mangledName, jsList);
+    String reflectiveName =
+        JS('String', '# + ":" + # + ":0"',
+           n(memberName), positionalArguments.length);
+    // We can safely pass positionalArguments to _invoke as it will wrap it in
+    // a JSArray if needed.
+    return _invoke(memberName, JSInvocationMirror.METHOD, reflectiveName,
+                   positionalArguments);
   }
 
   InstanceMirror _invoke(Symbol name,
                          int type,
-                         String mangledName,
+                         String reflectiveName,
                          List arguments) {
-    disableTreeShaking();
-    // TODO(ahe): Get the argument names.
-    List<String> argumentNames = [];
-    Invocation invocation = createUnmangledInvocationMirror(
-        name, mangledName, type, arguments, argumentNames);
+    String cacheName = Primitives.mirrorInvokeCacheName;
+    var cache = JS('', r'#.constructor[#]', reflectee, cacheName);
+    if (cache == null) {
+      cache = JsCache.allocate();
+      JS('void', r'#.constructor[#] = #', reflectee, cacheName, cache);
+    }
+    var cacheEntry = JsCache.fetch(cache, reflectiveName);
+    var result;
+    Invocation invocation;
+    if (cacheEntry == null) {
+      disableTreeShaking();
+      String mangledName = reflectiveNames[reflectiveName];
+      // TODO(ahe): Get the argument names.
+      List<String> argumentNames = [];
+      // TODO(ahe): We don't need to create an invocation mirror here. The
+      // logic from JSInvocationMirror.getCachedInvocation could easily be
+      // inlined here.
+      invocation = createUnmangledInvocationMirror(
+          name, mangledName, type, arguments, argumentNames);
 
-    return reflect(delegate(invocation));
+      cacheEntry =
+          JSInvocationMirror.getCachedInvocation(invocation, reflectee);
+      JsCache.update(cache, reflectiveName, cacheEntry);
+    }
+    if (cacheEntry.isNoSuchMethod) {
+      if (invocation == null) {
+        String mangledName = reflectiveNames[reflectiveName];
+        // TODO(ahe): Get the argument names.
+        List<String> argumentNames = [];
+        invocation = createUnmangledInvocationMirror(
+            name, mangledName, type, arguments, argumentNames);
+      }
+      return reflect(cacheEntry.invokeOn(reflectee, invocation));
+    } else {
+      return reflect(cacheEntry.invokeOn(reflectee, arguments));
+    }
   }
 
   InstanceMirror setField(Symbol fieldName, Object arg) {
     String reflectiveName = '${n(fieldName)}=';
-    String mangledName = reflectiveNames[reflectiveName];
-    _invoke(s(reflectiveName), JSInvocationMirror.SETTER, mangledName, [arg]);
+    _invoke(
+        s(reflectiveName), JSInvocationMirror.SETTER, reflectiveName, [arg]);
     return reflect(arg);
   }
 
   InstanceMirror getField(Symbol fieldName) {
     String reflectiveName = n(fieldName);
-    String mangledName = reflectiveNames[reflectiveName];
-    return _invoke(fieldName, JSInvocationMirror.GETTER, mangledName, []);
+    return _invoke(fieldName, JSInvocationMirror.GETTER, reflectiveName, []);
   }
 
   delegate(Invocation invocation) {
@@ -507,10 +676,18 @@
   final _jsConstructorOrInterceptor;
   final String _fieldsDescriptor;
   final List _fieldsMetadata;
+  final _jsConstructorCache = JsCache.allocate();
   List _metadata;
-  JsClassMirror _superclass;
+  ClassMirror _superclass;
   List<JsMethodMirror> _cachedMethods;
   List<JsVariableMirror> _cachedFields;
+  UnmodifiableMapView<Symbol, MethodMirror> _cachedConstructors;
+  UnmodifiableMapView<Symbol, MethodMirror> _cachedMethodsMap;
+  UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters;
+  UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters;
+  UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables;
+  UnmodifiableMapView<Symbol, Mirror> _cachedMembers;
+  UnmodifiableListView<InstanceMirror> _cachedMetadata;
 
   // Set as side-effect of accessing JsLibraryMirror.classes.
   JsLibraryMirror _owner;
@@ -533,13 +710,15 @@
   }
 
   Map<Symbol, MethodMirror> get constructors {
-    var result = new Map<Symbol, MethodMirror>();
+    if (_cachedConstructors != null) return _cachedConstructors;
+    var result = new Map();
     for (JsMethodMirror method in _methods) {
       if (method.isConstructor) {
         result[method.simpleName] = method;
       }
     }
-    return result;
+    return _cachedConstructors =
+        new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
   List<JsMethodMirror> get _methods {
@@ -618,20 +797,23 @@
   }
 
   Map<Symbol, MethodMirror> get methods {
-    var result = new Map<Symbol, MethodMirror>();
+    if (_cachedMethodsMap != null) return _cachedMethodsMap;
+    var result = new Map();
     for (JsMethodMirror method in _methods) {
       if (!method.isConstructor && !method.isGetter && !method.isSetter) {
         result[method.simpleName] = method;
       }
     }
-    return result;
+    return _cachedMethodsMap =
+        new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
   Map<Symbol, MethodMirror> get getters {
+    if (_cachedGetters != null) return _cachedGetters;
     // TODO(ahe): This is a hack to remove getters corresponding to a field.
     var fields = variables;
 
-    var result = new Map<Symbol, MethodMirror>();
+    var result = new Map();
     for (JsMethodMirror method in _methods) {
       if (method.isGetter) {
 
@@ -641,14 +823,16 @@
         result[method.simpleName] = method;
       }
     }
-    return result;
+    return _cachedGetters =
+        new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
   Map<Symbol, MethodMirror> get setters {
+    if (_cachedSetters != null) return _cachedSetters;
     // TODO(ahe): This is a hack to remove setters corresponding to a field.
     var fields = variables;
 
-    var result = new Map<Symbol, MethodMirror>();
+    var result = new Map();
     for (JsMethodMirror method in _methods) {
       if (method.isSetter) {
 
@@ -660,19 +844,23 @@
         result[method.simpleName] = method;
       }
     }
-    return result;
+    return _cachedSetters =
+        new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
   Map<Symbol, VariableMirror> get variables {
-    var result = new Map<Symbol, VariableMirror>();
+    if (_cachedVariables != null) return _cachedVariables;
+    var result = new Map();
     for (JsVariableMirror mirror in _fields) {
       result[mirror.simpleName] = mirror;
     }
-    return result;
+    return _cachedVariables =
+        new UnmodifiableMapView<Symbol, VariableMirror>(result);
   }
 
   Map<Symbol, Mirror> get members {
-    Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(variables);
+    if (_cachedMembers != null) return _cachedMembers;
+    Map<Symbol, Mirror> result = new Map.from(variables);
     for (JsMethodMirror method in _methods) {
       if (method.isSetter) {
         String name = n(method.simpleName);
@@ -683,7 +871,7 @@
       // Use putIfAbsent to filter-out getters corresponding to variables.
       result.putIfAbsent(method.simpleName, () => method);
     }
-    return result;
+    return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(result);
   }
 
   InstanceMirror setField(Symbol fieldName, Object arg) {
@@ -724,15 +912,20 @@
     if (namedArguments != null && !namedArguments.isEmpty) {
       throw new UnsupportedError('Named arguments are not implemented.');
     }
-    JsMethodMirror mirror = constructors.values.firstWhere(
-        (m) => m.constructorName == constructorName,
-        orElse: () {
-          // TODO(ahe): Pass namedArguments when NoSuchMethodError has been
-          // fixed to use Symbol.
-          // TODO(ahe): What receiver to use?
-          throw new NoSuchMethodError(
-              owner, n(constructorName), positionalArguments, null);
-        });
+    JsMethodMirror mirror =
+        JsCache.fetch(_jsConstructorCache, n(constructorName));
+    if (mirror == null) {
+      mirror = constructors.values.firstWhere(
+          (m) => m.constructorName == constructorName,
+          orElse: () {
+            // TODO(ahe): Pass namedArguments when NoSuchMethodError has been
+            // fixed to use Symbol.
+            // TODO(ahe): What receiver to use?
+            throw new NoSuchMethodError(
+                owner, n(constructorName), positionalArguments, null);
+          });
+      JsCache.update(_jsConstructorCache, n(constructorName), mirror);
+    }
     return reflect(mirror._invoke(positionalArguments, namedArguments));
   }
 
@@ -770,18 +963,28 @@
   }
 
   List<InstanceMirror> get metadata {
+    if (_cachedMetadata != null) return _cachedMetadata;
     if (_metadata == null) {
       _metadata = extractMetadata(JS('', '#.prototype', _jsConstructor));
     }
-    return _metadata.map(reflect).toList();
+    return _cachedMetadata =
+        new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect));
   }
 
   ClassMirror get superclass {
     if (_superclass == null) {
       var superclassName = _fieldsDescriptor.split(';')[0];
-      // Use _superclass == this to represent class with no superclass (Object).
-      _superclass = (superclassName == '')
-          ? this : reflectClassByMangledName(superclassName);
+      var mixins = superclassName.split('+');
+      if (mixins.length > 1) {
+        if (mixins.length != 2) {
+          throw new RuntimeError('Strange mixin: $_fieldsDescriptor');
+        }
+        _superclass = reflectClassByMangledName(mixins[0]);
+      } else {
+        // Use _superclass == this to represent class with no superclass (Object).
+        _superclass = (superclassName == '')
+            ? this : reflectClassByMangledName(superclassName);
+      }
     }
     return _superclass == this ? null : _superclass;
   }
@@ -806,15 +1009,15 @@
     return reflect(mirror._invoke(positionalArguments, namedArguments));
   }
 
+  bool get isOriginalDeclaration => true;
+
+  ClassMirror get originalDeclaration => this;
+
   // TODO(ahe): Implement these.
   List<ClassMirror> get superinterfaces => throw new UnimplementedError();
   Map<Symbol, TypeVariableMirror> get typeVariables
       => throw new UnimplementedError();
   Map<Symbol, TypeMirror> get typeArguments => throw new UnimplementedError();
-  bool get isOriginalDeclaration => throw new UnimplementedError();
-  ClassMirror get originalDeclaration => throw new UnimplementedError();
-  bool get isClass => throw new UnimplementedError();
-  ClassMirror get defaultFactory => throw new UnimplementedError();
 }
 
 class JsVariableMirror extends JsDeclarationMirror implements VariableMirror {
@@ -913,6 +1116,10 @@
       : super(reflectee);
 
   MethodMirror get function {
+    String cacheName = Primitives.mirrorFunctionCacheName;
+    JsMethodMirror cachedFunction =
+        JS('JsMethodMirror|Null', r'#.constructor[#]', reflectee, cacheName);
+    if (cachedFunction != null) return cachedFunction;
     disableTreeShaking();
     // TODO(ahe): What about optional parameters (named or not).
     var extractCallName = JS('', r'''
@@ -932,15 +1139,17 @@
     if (reflectee is BoundClosure) {
       var target = BoundClosure.targetOf(reflectee);
       var self = BoundClosure.selfOf(reflectee);
-      return new JsMethodMirror(
+      cachedFunction = new JsMethodMirror(
           s(target), JS('', '#[#]', self, target), parameterCount,
           false, false, isStatic, false, false);
     } else {
       var jsFunction = JS('', '#[#]', reflectee, callName);
-      return new JsMethodMirror(
+      cachedFunction = new JsMethodMirror(
           s(callName), jsFunction, parameterCount,
           false, false, isStatic, false, false);
     }
+    JS('void', r'#.constructor[#] = #', reflectee, cacheName, cachedFunction);
+    return cachedFunction;
   }
 
   InstanceMirror apply(List positionalArguments,
@@ -974,7 +1183,7 @@
   DeclarationMirror _owner;
   List _metadata;
   var _returnType;
-  var _parameters;
+  UnmodifiableListView<ParameterMirror> _parameters;
 
   JsMethodMirror(Symbol simpleName,
                  this._jsFunction,
@@ -1016,8 +1225,9 @@
   String get _prettyName => 'MethodMirror';
 
   List<ParameterMirror> get parameters {
+    if (_parameters != null) return _parameters;
     metadata; // Compute _parameters as a side-effect of extracting metadata.
-    return new List<ParameterMirror>.from(_parameters);
+    return _parameters;
   }
 
   DeclarationMirror get owner => _owner;
@@ -1030,19 +1240,26 @@
   List<InstanceMirror> get metadata {
     if (_metadata == null) {
       var raw = extractMetadata(_jsFunction);
-      _returnType = raw[0];
-      int parameterLength = 1 + _parameterCount * 2;
-      var formals = new List<ParameterMirror>(_parameterCount);
-      int formalsCount = 0;
-      for (int i = 1; i < parameterLength; i += 2) {
-        var name = raw[i];
-        var type = raw[i + 1];
-        formals[formalsCount++] = new JsParameterMirror(name, this, type);
+      var formals = new List(_parameterCount);
+      if (!raw.isEmpty) {
+        _returnType = raw[0];
+        int parameterLength = 1 + _parameterCount * 2;
+        int formalsCount = 0;
+        for (int i = 1; i < parameterLength; i += 2) {
+          var name = raw[i];
+          var type = raw[i + 1];
+          formals[formalsCount++] = new JsParameterMirror(name, this, type);
+        }
+        raw = raw.sublist(parameterLength);
+      } else {
+        for (int i = 0; i < _parameterCount; i++) {
+          formals[i] = new JsParameterMirror('argument$i', this, null);
+        }
       }
-      _parameters = formals;
-      _metadata = raw.sublist(parameterLength);
+      _parameters = new UnmodifiableListView<ParameterMirror>(formals);
+      _metadata = new UnmodifiableListView(raw.map(reflect));
     }
-    return _metadata.map(reflect).toList();
+    return _metadata;
   }
 
   Symbol get constructorName {
@@ -1131,6 +1348,9 @@
 
   // TODO(ahe): Implement this.
   get defaultValue => null;
+
+  // TODO(ahe): Implement this.
+  List<InstanceMirror> get metadata => throw new UnimplementedError();
 }
 
 TypeMirror typeMirrorFromRuntimeTypeRepresentation(type) {
@@ -1222,3 +1442,43 @@
     return false;
   }
 }
+
+// Copied from package "unmodifiable_collection".
+// TODO(ahe): Lobby to get it added to dart:collection.
+class UnmodifiableMapView<K, V> implements Map<K, V> {
+  Map<K, V> _source;
+  UnmodifiableMapView(Map<K, V> source) : _source = source;
+
+  static void _throw() {
+    throw new UnsupportedError("Cannot modify an unmodifiable Map");
+  }
+
+  int get length => _source.length;
+
+  bool get isEmpty => _source.isEmpty;
+
+  bool get isNotEmpty => _source.isNotEmpty;
+
+  V operator [](K key) => _source[key];
+
+  bool containsKey(K key) => _source.containsKey(key);
+
+  bool containsValue(V value) => _source.containsValue(value);
+
+  void forEach(void f(K key, V value)) => _source.forEach(f);
+
+  Iterable<K> get keys => _source.keys;
+
+  Iterable<V> get values => _source.values;
+
+
+  void operator []=(K key, V value) => _throw();
+
+  V putIfAbsent(K key, V ifAbsent()) { _throw(); }
+
+  void addAll(Map<K, V> other) => _throw();
+
+  V remove(K key) { _throw(); }
+
+  void clear() => _throw();
+}
diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart
index 9927806..f8491d1 100644
--- a/sdk/lib/_internal/pub/bin/pub.dart
+++ b/sdk/lib/_internal/pub/bin/pub.dart
@@ -14,7 +14,6 @@
 import '../lib/src/io.dart';
 import '../lib/src/log.dart' as log;
 import '../lib/src/sdk.dart' as sdk;
-import '../lib/src/system_cache.dart';
 import '../lib/src/utils.dart';
 
 final pubArgParser = initArgParser();
diff --git a/sdk/lib/_internal/pub/lib/src/command/help.dart b/sdk/lib/_internal/pub/lib/src/command/help.dart
index a53c575..854d3cd 100644
--- a/sdk/lib/_internal/pub/lib/src/command/help.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/help.dart
@@ -9,7 +9,6 @@
 
 import '../command.dart';
 import '../exit_codes.dart' as exit_codes;
-import '../io.dart';
 import '../log.dart' as log;
 
 /// Handles the `help` pub command.
diff --git a/sdk/lib/_internal/pub/lib/src/command/install.dart b/sdk/lib/_internal/pub/lib/src/command/install.dart
index f5621de..ac17a69 100644
--- a/sdk/lib/_internal/pub/lib/src/command/install.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/install.dart
@@ -6,8 +6,6 @@
 
 import 'dart:async';
 
-import 'package:args/args.dart';
-
 import '../command.dart';
 import '../entrypoint.dart';
 import '../log.dart' as log;
diff --git a/sdk/lib/_internal/pub/lib/src/command/lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
index 23f4c97..4a7b2ac 100644
--- a/sdk/lib/_internal/pub/lib/src/command/lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -6,16 +6,12 @@
 
 import 'dart:async';
 import 'dart:io';
-import 'dart:json';
 
-import 'package:args/args.dart';
 import 'package:http/http.dart' as http;
-import 'package:path/path.dart' as path;
 
 import '../command.dart';
 import '../directory_tree.dart';
 import '../exit_codes.dart' as exit_codes;
-import '../git.dart' as git;
 import '../http.dart';
 import '../io.dart';
 import '../log.dart' as log;
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
index ce8db31..69d92a1 100644
--- a/sdk/lib/_internal/pub/lib/src/command/serve.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -78,14 +78,14 @@
       // are added or modified.
 
       HttpServer.bind("localhost", port).then((server) {
-        log.message("Serving ${entrypoint.root.name} "
-                    "on http://localhost:${server.port}");
-
         // Add all of the visible files.
         for (var package in provider.packages) {
           barback.updateSources(provider.listAssets(package));
         }
 
+        log.message("Serving ${entrypoint.root.name} "
+            "on http://localhost:${server.port}");
+
         server.listen((request) {
           var id = getIdFromUri(request.uri);
           if (id == null) {
@@ -93,14 +93,31 @@
           }
 
           barback.getAssetById(id).then((asset) {
-            log.message(
-                "$_green${request.method}$_none ${request.uri} -> $asset");
-            // TODO(rnystrom): Set content-type based on asset type.
-            return request.response.addStream(asset.read()).then((_) {
+            return validateStream(asset.read()).then((stream) {
+              log.message(
+                  "$_green${request.method}$_none ${request.uri} -> $asset");
+              // TODO(rnystrom): Set content-type based on asset type.
+              return request.response.addStream(stream).then((_) {
+                request.response.close();
+              });
+            }).catchError((error) {
+              log.error("$_red${request.method}$_none "
+                  "${request.uri} -> $error");
+
+              // If we couldn't read the asset, handle the error gracefully.
+              if (error is FileException) {
+                // Assume this means the asset was a file-backed source asset
+                // and we couldn't read it, so treat it like a missing asset.
+                notFound(request, error);
+                return;
+              }
+
+              // Otherwise, it's some internal error.
+              request.response.statusCode = 500;
+              request.response.reasonPhrase = "Internal Error";
+              request.response.write(error);
               request.response.close();
             });
-            // TODO(rnystrom): Serve up a 500 if we get an error reading the
-            // asset.
           }).catchError((error) {
             log.error("$_red${request.method}$_none ${request.uri} -> $error");
             if (error is! AssetNotFoundException) {
diff --git a/sdk/lib/_internal/pub/lib/src/command/update.dart b/sdk/lib/_internal/pub/lib/src/command/update.dart
index e47c80b..5c3b4ed 100644
--- a/sdk/lib/_internal/pub/lib/src/command/update.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/update.dart
@@ -6,8 +6,6 @@
 
 import 'dart:async';
 
-import 'package:args/args.dart';
-
 import '../command.dart';
 import '../entrypoint.dart';
 import '../log.dart' as log;
diff --git a/sdk/lib/_internal/pub/lib/src/command/uploader.dart b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
index 4ede2c1..f3cf290 100644
--- a/sdk/lib/_internal/pub/lib/src/command/uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
@@ -7,18 +7,15 @@
 import 'dart:async';
 import 'dart:io';
 
-import 'package:args/args.dart';
 import 'package:path/path.dart' as path;
 
 import '../command.dart';
 import '../entrypoint.dart';
 import '../exit_codes.dart' as exit_codes;
 import '../http.dart';
-import '../io.dart';
 import '../log.dart' as log;
 import '../oauth2.dart' as oauth2;
 import '../source/hosted.dart';
-import '../utils.dart';
 
 /// Handles the `uploader` pub command.
 class UploaderCommand extends PubCommand {
diff --git a/sdk/lib/_internal/pub/lib/src/dart.dart b/sdk/lib/_internal/pub/lib/src/dart.dart
index ce4d59d..d1e3b03 100644
--- a/sdk/lib/_internal/pub/lib/src/dart.dart
+++ b/sdk/lib/_internal/pub/lib/src/dart.dart
@@ -6,16 +6,10 @@
 library pub.dart;
 
 import 'dart:async';
-import 'dart:io';
-import 'dart:math' as math;
 
 import 'package:analyzer_experimental/analyzer.dart';
 import 'package:path/path.dart' as path;
 import '../../../compiler/compiler.dart' as compiler;
-import '../../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js
-    show analyze, Dart2JsMirrorSystem;
-import '../../../compiler/implementation/mirrors/mirrors.dart'
-    show MirrorSystem;
 import '../../../compiler/implementation/source_file_provider.dart'
     show FormattingDiagnosticHandler, SourceFileProvider;
 import '../../../compiler/implementation/filenames.dart'
diff --git a/sdk/lib/_internal/pub/lib/src/directory_tree.dart b/sdk/lib/_internal/pub/lib/src/directory_tree.dart
index 1f07bc7..ad67e26 100644
--- a/sdk/lib/_internal/pub/lib/src/directory_tree.dart
+++ b/sdk/lib/_internal/pub/lib/src/directory_tree.dart
@@ -7,8 +7,6 @@
 
 import 'package:path/path.dart' as path;
 
-import 'log.dart' as log;
-
 /// Draws a directory tree for the given list of files. Given a list of files
 /// like:
 ///
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index b382b44..30f42f7 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -13,11 +13,8 @@
 import 'lock_file.dart';
 import 'log.dart' as log;
 import 'package.dart';
-import 'pubspec.dart';
-import 'sdk.dart' as sdk;
 import 'system_cache.dart';
 import 'utils.dart';
-import 'version.dart';
 import 'solver/version_solver.dart';
 
 /// Pub operates over a directed graph of dependencies that starts at a root
diff --git a/sdk/lib/_internal/pub/lib/src/error_group.dart b/sdk/lib/_internal/pub/lib/src/error_group.dart
index b49b45a..1130ef9 100644
--- a/sdk/lib/_internal/pub/lib/src/error_group.dart
+++ b/sdk/lib/_internal/pub/lib/src/error_group.dart
@@ -6,8 +6,6 @@
 
 import 'dart:async';
 
-import 'utils.dart';
-
 /// An [ErrorGroup] entangles the errors of multiple [Future]s and [Stream]s
 /// with one another. This allows APIs to expose multiple [Future]s and
 /// [Stream]s that have identical error conditions without forcing API consumers
diff --git a/sdk/lib/_internal/pub/lib/src/git.dart b/sdk/lib/_internal/pub/lib/src/git.dart
index 9e946e2..e94e493 100644
--- a/sdk/lib/_internal/pub/lib/src/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/git.dart
@@ -8,7 +8,6 @@
 import 'dart:async';
 import 'io.dart';
 import 'log.dart' as log;
-import 'utils.dart';
 
 /// Tests whether or not the git command-line app is available for use.
 Future<bool> get isInstalled {
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 4e6b695..5847fed 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -8,13 +8,10 @@
 import 'dart:async';
 import 'dart:collection';
 import 'dart:io';
-import 'dart:isolate';
-import 'dart:json';
 
 import 'package:path/path.dart' as path;
 import 'package:http/http.dart' show ByteStream;
 import 'error_group.dart';
-import 'exit_codes.dart' as exit_codes;
 import 'log.dart' as log;
 import 'sdk.dart' as sdk;
 import 'utils.dart';
@@ -312,7 +309,13 @@
 /// Renames (i.e. moves) the directory [from] to [to].
 void renameDir(String from, String to) {
   log.io("Renaming directory $from to $to.");
-  new Directory(from).renameSync(to);
+  try {
+    new Directory(from).renameSync(to);
+  } on IOException catch (error) {
+    // Ensure that [to] isn't left in an inconsistent state. See issue 12436.
+    if (entryExists(to)) deleteEntry(to);
+    rethrow;
+  }
 }
 
 /// Creates a new symlink at path [symlink] that points to [target]. Returns a
diff --git a/sdk/lib/_internal/pub/lib/src/lock_file.dart b/sdk/lib/_internal/pub/lib/src/lock_file.dart
index 85b63a8..1799191 100644
--- a/sdk/lib/_internal/pub/lib/src/lock_file.dart
+++ b/sdk/lib/_internal/pub/lib/src/lock_file.dart
@@ -4,12 +4,9 @@
 
 library pub.lock_file;
 
-import 'dart:collection';
-
 import 'package:yaml/yaml.dart';
 
 import 'io.dart';
-import 'log.dart' as log;
 import 'package.dart';
 import 'source_registry.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart
index 315f189..63ed342 100644
--- a/sdk/lib/_internal/pub/lib/src/package.dart
+++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -4,8 +4,6 @@
 
 library pub.package;
 
-import 'dart:async';
-
 import 'package:path/path.dart' as path;
 
 import 'io.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart b/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
index 6243127..b1c2821 100644
--- a/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
+++ b/sdk/lib/_internal/pub/lib/src/pub_package_provider.dart
@@ -5,7 +5,6 @@
 library pub.pub_package_provider;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:barback/barback.dart';
 import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/source/git.dart b/sdk/lib/_internal/pub/lib/src/source/git.dart
index 262efc2..4064955 100644
--- a/sdk/lib/_internal/pub/lib/src/source/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/git.dart
@@ -10,10 +10,8 @@
 
 import '../git.dart' as git;
 import '../io.dart';
-import '../log.dart' as log;
 import '../package.dart';
 import '../source.dart';
-import '../source_registry.dart';
 import '../utils.dart';
 
 /// A package source that installs packages from Git repos.
diff --git a/sdk/lib/_internal/pub/lib/src/source/hosted.dart b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
index be7f835..7a0409f 100644
--- a/sdk/lib/_internal/pub/lib/src/source/hosted.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
@@ -17,7 +17,6 @@
 import '../package.dart';
 import '../pubspec.dart';
 import '../source.dart';
-import '../source_registry.dart';
 import '../utils.dart';
 import '../version.dart';
 
diff --git a/sdk/lib/_internal/pub/lib/src/source/path.dart b/sdk/lib/_internal/pub/lib/src/source/path.dart
index 6a9363a..d007f2e 100644
--- a/sdk/lib/_internal/pub/lib/src/source/path.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/path.dart
@@ -5,16 +5,12 @@
 library pub.source.path;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:path/path.dart' as path;
 
-import '../log.dart' as log;
-
 import '../io.dart';
 import '../package.dart';
 import '../pubspec.dart';
-import '../version.dart';
 import '../source.dart';
 import '../utils.dart';
 
diff --git a/sdk/lib/_internal/pub/lib/src/system_cache.dart b/sdk/lib/_internal/pub/lib/src/system_cache.dart
index b1cd1ac..7dafb8c 100644
--- a/sdk/lib/_internal/pub/lib/src/system_cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/system_cache.dart
@@ -4,7 +4,6 @@
 
 library pub.system_cache;
 
-import 'dart:io';
 import 'dart:async';
 
 import 'package:path/path.dart' as path;
@@ -13,14 +12,11 @@
 import 'io.dart' as io show createTempDir;
 import 'log.dart' as log;
 import 'package.dart';
-import 'pubspec.dart';
 import 'source/git.dart';
 import 'source/hosted.dart';
 import 'source/path.dart';
 import 'source.dart';
 import 'source_registry.dart';
-import 'utils.dart';
-import 'version.dart';
 
 /// The system-wide cache of installed packages.
 ///
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 6a048cf..d495516 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -7,7 +7,6 @@
 
 import 'dart:async';
 import 'dart:io';
-import 'dart:isolate';
 import 'dart:json' as json;
 import 'dart:mirrors';
 
@@ -168,6 +167,49 @@
       onError: (e) => completer.completeError(e));
 }
 
+/// Ensures that [stream] can emit at least one value successfully (or close
+/// without any values).
+///
+/// For example, reading asynchronously from a non-existent file will return a
+/// stream that fails on the first chunk. In order to handle that more
+/// gracefully, you may want to check that the stream looks like it's working
+/// before you pipe the stream to something else.
+///
+/// This lets you do that. It returns a [Future] that completes to a [Stream]
+/// emitting the same values and errors as [stream], but only if at least one
+/// value can be read successfully. If an error occurs before any values are
+/// emitted, the returned Future completes to that error.
+Future<Stream> validateStream(Stream stream) {
+  var completer = new Completer<Stream>();
+  var controller = new StreamController(sync: true);
+
+  StreamSubscription subscription;
+  subscription = stream.listen((value) {
+    // We got a value, so the stream is valid.
+    if (!completer.isCompleted) completer.complete(controller.stream);
+    controller.add(value);
+  }, onError: (error) {
+    // If the error came after values, it's OK.
+    if (completer.isCompleted) {
+      controller.addError(error);
+      return;
+    }
+
+    // Otherwise, the error came first and the stream is invalid.
+    completer.completeError(error);
+
+    // We don't be returning the stream at all in this case, so unsubscribe
+    // and swallow the error.
+    subscription.cancel();
+  }, onDone: () {
+    // It closed with no errors, so the stream is valid.
+    if (!completer.isCompleted) completer.complete(controller.stream);
+    controller.close();
+  });
+
+  return completer.future;
+}
+
 // TODO(nweiz): remove this when issue 7964 is fixed.
 /// Returns a [Future] that will complete to the first element of [stream].
 /// Unlike [Stream.first], this is safe to use with single-subscription streams.
diff --git a/sdk/lib/_internal/pub/lib/src/validator.dart b/sdk/lib/_internal/pub/lib/src/validator.dart
index c4a258f..98ef43e 100644
--- a/sdk/lib/_internal/pub/lib/src/validator.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator.dart
@@ -8,8 +8,6 @@
 
 import 'entrypoint.dart';
 import 'log.dart' as log;
-import 'io.dart';
-import 'system_cache.dart';
 import 'utils.dart';
 import 'validator/compiled_dartdoc.dart';
 import 'validator/dependency.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
index 3eaeec3..d6abf6d 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
@@ -10,7 +10,6 @@
 
 import '../entrypoint.dart';
 import '../io.dart';
-import '../utils.dart';
 import '../validator.dart';
 
 /// Validates that a package doesn't contain compiled Dartdoc
diff --git a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
index b447a8d..46e0015 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
@@ -7,11 +7,7 @@
 import 'dart:async';
 
 import '../entrypoint.dart';
-import '../http.dart';
 import '../package.dart';
-import '../source/hosted.dart';
-import '../source/path.dart';
-import '../utils.dart';
 import '../validator.dart';
 import '../version.dart';
 
diff --git a/sdk/lib/_internal/pub/lib/src/validator/directory.dart b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
index 65ad909..6039fc5 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/directory.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
@@ -10,7 +10,6 @@
 
 import '../entrypoint.dart';
 import '../io.dart';
-import '../utils.dart';
 import '../validator.dart';
 
 /// A validator that validates a package's top-level directories.
diff --git a/sdk/lib/_internal/pub/lib/src/validator/lib.dart b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
index 5a89359..98bed28 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/lib.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
@@ -5,14 +5,11 @@
 library pub.validator.lib;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:path/path.dart' as path;
 
 import '../entrypoint.dart';
 import '../io.dart';
-import '../system_cache.dart';
-import '../utils.dart';
 import '../validator.dart';
 
 // TODO(nweiz): When issue 7196 is fixed, complain about non-Dart files in lib.
diff --git a/sdk/lib/_internal/pub/lib/src/validator/license.dart b/sdk/lib/_internal/pub/lib/src/validator/license.dart
index e606752..222d693 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/license.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/license.dart
@@ -10,7 +10,6 @@
 
 import '../entrypoint.dart';
 import '../io.dart';
-import '../system_cache.dart';
 import '../validator.dart';
 
 /// A validator that checks that a LICENSE-like file exists.
diff --git a/sdk/lib/_internal/pub/lib/src/validator/name.dart b/sdk/lib/_internal/pub/lib/src/validator/name.dart
index 8e79ac1..1285fb1 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/name.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/name.dart
@@ -5,13 +5,11 @@
 library pub.validator.name;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:path/path.dart' as path;
 
 import '../entrypoint.dart';
 import '../io.dart';
-import '../utils.dart';
 import '../validator.dart';
 
 /// Dart reserved words, from the Dart spec.
diff --git a/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart b/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart
index 6cb1d83..e9d2d35 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart
@@ -7,9 +7,7 @@
 import 'dart:async';
 
 import '../entrypoint.dart';
-import '../system_cache.dart';
 import '../validator.dart';
-import '../version.dart';
 
 /// A validator that checks that the pubspec has valid "author" and "homepage"
 /// fields.
diff --git a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
index 1984ec8..28cccbd 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
@@ -7,11 +7,8 @@
 import 'dart:async';
 import 'dart:utf';
 
-import 'package:path/path.dart' as path;
-
 import '../entrypoint.dart';
 import '../io.dart';
-import '../utils.dart';
 import '../validator.dart';
 
 /// Validates that a package's README is valid utf-8.
diff --git a/sdk/lib/_internal/pub/lib/src/version.dart b/sdk/lib/_internal/pub/lib/src/version.dart
index c3943a6..0d25c73 100644
--- a/sdk/lib/_internal/pub/lib/src/version.dart
+++ b/sdk/lib/_internal/pub/lib/src/version.dart
@@ -9,9 +9,6 @@
 
 import 'dart:math';
 
-import 'utils.dart';
-
-
 /// Regex that matches a version number at the beginning of a string.
 final _START_VERSION = new RegExp(
     r'^'                                        // Start at beginning.
diff --git a/sdk/lib/_internal/pub/test/deploy/ignores_non_entrypoint_dart_files_test.dart b/sdk/lib/_internal/pub/test/deploy/ignores_non_entrypoint_dart_files_test.dart
index 084ae8a..8d2b06a 100644
--- a/sdk/lib/_internal/pub/test/deploy/ignores_non_entrypoint_dart_files_test.dart
+++ b/sdk/lib/_internal/pub/test/deploy/ignores_non_entrypoint_dart_files_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:path/path.dart' as path;
-import 'package:scheduled_test/scheduled_test.dart';
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
diff --git a/sdk/lib/_internal/pub/test/descriptor.dart b/sdk/lib/_internal/pub/test/descriptor.dart
index 7893f88..1487aff 100644
--- a/sdk/lib/_internal/pub/test/descriptor.dart
+++ b/sdk/lib/_internal/pub/test/descriptor.dart
@@ -7,7 +7,6 @@
 
 import 'package:oauth2/oauth2.dart' as oauth2;
 import 'package:scheduled_test/scheduled_server.dart';
-import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/descriptor.dart';
 
 import '../lib/src/utils.dart';
diff --git a/sdk/lib/_internal/pub/test/descriptor/tar.dart b/sdk/lib/_internal/pub/test/descriptor/tar.dart
index 658bb4d..2a04a03 100644
--- a/sdk/lib/_internal/pub/test/descriptor/tar.dart
+++ b/sdk/lib/_internal/pub/test/descriptor/tar.dart
@@ -4,7 +4,6 @@
 
 library descriptor.tar;
 
-import 'dart:io';
 import 'dart:async';
 
 import 'package:path/path.dart' as path;
@@ -12,7 +11,6 @@
 import 'package:scheduled_test/descriptor.dart';
 
 import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 
 /// Describes a tar file and its contents.
 class TarFileDescriptor extends DirectoryDescriptor
diff --git a/sdk/lib/_internal/pub/test/dev_dependency_test.dart b/sdk/lib/_internal/pub/test/dev_dependency_test.dart
index 0b5e480..e2dec6b 100644
--- a/sdk/lib/_internal/pub/test/dev_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/dev_dependency_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:path/path.dart' as path;
-
 import 'descriptor.dart' as d;
 import 'test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
index f80f4bd..bc72cc0 100644
--- a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart
index 25bf4b6..6b383b3 100644
--- a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/hosted/offline_test.dart b/sdk/lib/_internal/pub/test/hosted/offline_test.dart
index 20738f7..d6f96d3 100644
--- a/sdk/lib/_internal/pub/test/hosted/offline_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/offline_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/hosted/remove_removed_dependency_test.dart b/sdk/lib/_internal/pub/test/hosted/remove_removed_dependency_test.dart
index fb25e72..be65989 100644
--- a/sdk/lib/_internal/pub/test/hosted/remove_removed_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/remove_removed_dependency_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/hosted/remove_removed_transitive_dependency_test.dart b/sdk/lib/_internal/pub/test/hosted/remove_removed_transitive_dependency_test.dart
index 3a797e2..d630810 100644
--- a/sdk/lib/_internal/pub/test/hosted/remove_removed_transitive_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/remove_removed_transitive_dependency_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart b/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart
index 51cff5f..1514a45 100644
--- a/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import 'package:path/path.dart' as path;
 
 import '../descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart
index 9fd1e6a..7474772 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart
index b941083..5e244ce 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart
index e3966af..47aacf4 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_test.dart
index e9d7bc0..0e86ce2 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart
index f015b74..1c33546 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart
index 8f9b823..a62d412 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart
index dc367d9..f1b0041 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import 'package:scheduled_test/scheduled_test.dart';
 
 import '../../descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart
index 2c93e28..2d4fef9 100644
--- a/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart b/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart
index 0753135..1f68492 100644
--- a/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart b/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart
index cbf3f56..3a75a0d 100644
--- a/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import 'package:path/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart b/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart
index 26116b1..6baa826 100644
--- a/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart
index 55f28fe..fd05528 100644
--- a/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart b/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart
index b68e8ba..bf9194a 100644
--- a/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart b/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart
index 96de4da..3e70bb9 100644
--- a/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart
index dee49ae..c80ee31 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart
@@ -4,10 +4,8 @@
 
 library pub_tests;
 
-import 'package:path/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
 
-import '../../../lib/src/io.dart';
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart b/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart
index 808f122..57795c6 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/install_test.dart b/sdk/lib/_internal/pub/test/install/hosted/install_test.dart
index 1151f97..342a5f3 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/install_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/install_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart b/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart
index 2ac11db..1ee3796 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart b/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart
index 2d03b9c..e456a98 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'package:path/path.dart' as path;
-
-import '../../../lib/src/io.dart';
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart b/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart
index 37dc3a1..13f52e4 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart
index eab5c9b..63eacf3 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart
index 73f5c7d..186e490 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart
index e6351da..9fc7647 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import 'package:path/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart
index 06b104b..b1d68c2 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart
index 4a6e1875..b6145a1c 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart b/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart
index 5ca3197..703e7e2 100644
--- a/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart
@@ -3,9 +3,7 @@
 // BSD-style license that can be found in the LICENSE d.file.
 
 import 'package:path/path.dart' as path;
-import 'package:scheduled_test/scheduled_test.dart';
 
-import '../../../lib/src/io.dart';
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart b/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart
index 549046b..6e2e438 100644
--- a/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart
@@ -4,7 +4,6 @@
 
 import 'package:path/path.dart' as path;
 
-import '../../../lib/src/exit_codes.dart' as exit_codes;
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart
index ccdfa07..76ff65c 100644
--- a/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart
@@ -2,10 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE d.file.
 
-import 'dart:io';
-
 import 'package:path/path.dart' as path;
-import 'package:scheduled_test/scheduled_test.dart';
 
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
diff --git a/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart b/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
index f97f345..3137dad 100644
--- a/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
@@ -2,10 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE d.file.
 
-import 'dart:io';
-
 import 'package:path/path.dart' as path;
-import 'package:scheduled_test/scheduled_test.dart';
 
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
diff --git a/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart b/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
index 1207ff0..dc44cd7 100644
--- a/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE d.file.
 
 import 'package:path/path.dart' as path;
-import 'package:scheduled_test/scheduled_test.dart';
 
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
diff --git a/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart b/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart
index 06fb3da..21b3334 100644
--- a/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart
@@ -2,9 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE d.file.
 
-import 'package:path/path.dart' as path;
-
-import '../../../lib/src/exit_codes.dart' as exit_codes;
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart b/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart
index 7aac751..07047e9 100644
--- a/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart
@@ -6,7 +6,6 @@
 
 import 'package:path/path.dart' as path;
 
-import '../../../lib/src/exit_codes.dart' as exit_codes;
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart b/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
index 53e49b8..9894f7e86 100644
--- a/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE d.file.
 
-import 'dart:io';
-
 import 'package:path/path.dart' as path;
 
 import '../../descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart b/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart
index 7483dec..510780a 100644
--- a/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart
@@ -6,8 +6,6 @@
 
 import 'dart:io';
 
-import 'package:scheduled_test/scheduled_test.dart';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/install/switch_source_test.dart b/sdk/lib/_internal/pub/test/install/switch_source_test.dart
index 03f2ebc..e2c5280 100644
--- a/sdk/lib/_internal/pub/test/install/switch_source_test.dart
+++ b/sdk/lib/_internal/pub/test/install/switch_source_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/io_test.dart b/sdk/lib/_internal/pub/test/io_test.dart
index 55e3a27..bc8d708 100644
--- a/sdk/lib/_internal/pub/test/io_test.dart
+++ b/sdk/lib/_internal/pub/test/io_test.dart
@@ -11,7 +11,6 @@
 import 'package:unittest/unittest.dart';
 
 import '../lib/src/io.dart';
-import '../lib/src/utils.dart';
 import 'test_pub.dart';
 
 main() {
diff --git a/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_doesnt_redirect_test.dart b/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
index 82550f1..dc8d4110 100644
--- a/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
diff --git a/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_provides_an_error_test.dart b/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_provides_an_error_test.dart
index 348f80d..d574d74 100644
--- a/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_provides_an_error_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/cloud_storage_upload_provides_an_error_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io';
-import 'dart:json' as json;
 
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
diff --git a/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart b/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
index 4f0ddca..26231e3 100644
--- a/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
@@ -2,15 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
-import 'package:scheduled_test/scheduled_server.dart';
 
 import '../../lib/src/exit_codes.dart' as exit_codes;
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/force_does_not_publish_if_there_are_errors_test.dart b/sdk/lib/_internal/pub/test/lish/force_does_not_publish_if_there_are_errors_test.dart
index e599c26..4e85a6c 100644
--- a/sdk/lib/_internal/pub/test/lish/force_does_not_publish_if_there_are_errors_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/force_does_not_publish_if_there_are_errors_test.dart
@@ -2,14 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/package_creation_provides_invalid_json_test.dart b/sdk/lib/_internal/pub/test/lish/package_creation_provides_invalid_json_test.dart
index c4a1be5..43af294 100644
--- a/sdk/lib/_internal/pub/test/lish/package_creation_provides_invalid_json_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/package_creation_provides_invalid_json_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
diff --git a/sdk/lib/_internal/pub/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart b/sdk/lib/_internal/pub/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart
index e998bd9..c9c75fb 100644
--- a/sdk/lib/_internal/pub/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart
@@ -2,14 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/package_validation_has_an_error_test.dart b/sdk/lib/_internal/pub/test/lish/package_validation_has_an_error_test.dart
index d656117..b39694e 100644
--- a/sdk/lib/_internal/pub/test/lish/package_validation_has_an_error_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/package_validation_has_an_error_test.dart
@@ -2,14 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_a_warning_test.dart b/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_a_warning_test.dart
index 401d3b9..4509f12 100644
--- a/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_a_warning_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_a_warning_test.dart
@@ -2,14 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_no_warnings_test.dart b/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_no_warnings_test.dart
index 82ead77..9d4d1cb 100644
--- a/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_no_warnings_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/preview_package_validation_has_no_warnings_test.dart
@@ -2,14 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/upload_form_provides_an_error_test.dart b/sdk/lib/_internal/pub/test/lish/upload_form_provides_an_error_test.dart
index c2d753b..a02193c 100644
--- a/sdk/lib/_internal/pub/test/lish/upload_form_provides_an_error_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/upload_form_provides_an_error_test.dart
@@ -9,7 +9,6 @@
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/upload_form_provides_invalid_json_test.dart b/sdk/lib/_internal/pub/test/lish/upload_form_provides_invalid_json_test.dart
index 3a1b2cb..21ca53a 100644
--- a/sdk/lib/_internal/pub/test/lish/upload_form_provides_invalid_json_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/upload_form_provides_invalid_json_test.dart
@@ -2,14 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:json' as json;
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/lish/utils.dart b/sdk/lib/_internal/pub/test/lish/utils.dart
index 6ee3f5e..70020cf 100644
--- a/sdk/lib/_internal/pub/test/lish/utils.dart
+++ b/sdk/lib/_internal/pub/test/lish/utils.dart
@@ -11,7 +11,6 @@
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../../lib/src/io.dart';
-import '../test_pub.dart';
 
 void handleUploadForm(ScheduledServer server, [Map body]) {
   server.handle('GET', '/api/packages/versions/new', (request) {
diff --git a/sdk/lib/_internal/pub/test/lock_file_test.dart b/sdk/lib/_internal/pub/test/lock_file_test.dart
index 2145bb18..493741e 100644
--- a/sdk/lib/_internal/pub/test/lock_file_test.dart
+++ b/sdk/lib/_internal/pub/test/lock_file_test.dart
@@ -11,7 +11,6 @@
 import '../lib/src/package.dart';
 import '../lib/src/source.dart';
 import '../lib/src/source_registry.dart';
-import '../lib/src/utils.dart';
 import '../lib/src/version.dart';
 import 'test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/oauth2/utils.dart b/sdk/lib/_internal/pub/test/oauth2/utils.dart
index 7544506..a67e2bc 100644
--- a/sdk/lib/_internal/pub/test/oauth2/utils.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/utils.dart
@@ -14,7 +14,6 @@
 
 import '../../lib/src/io.dart';
 import '../../lib/src/utils.dart';
-import '../test_pub.dart';
 
 void authorizePub(ScheduledProcess pub, ScheduledServer server,
     [String accessToken="access token"]) {
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart
index 574117b..3ef06ec 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart
@@ -3,13 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io';
-import 'dart:json' as json;
 
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
-import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
index 35653ff..0fd9290 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
@@ -3,16 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io';
-import 'dart:json' as json;
 
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
-import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
index bbfdc64..08e1396 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
@@ -9,7 +9,6 @@
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
index 17eed6f..2155a89 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
@@ -9,10 +9,8 @@
 import 'package:scheduled_test/scheduled_server.dart';
 
 import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
index 0961868..a7ce025 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
@@ -3,13 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io';
-import 'dart:json' as json;
 
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
-import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
index 1790e85..1e931ce 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
@@ -7,8 +7,6 @@
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
-import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
index f670fe1..bbe3c3a 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
@@ -8,11 +8,8 @@
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
-import '../../lib/src/io.dart';
-import '../../lib/src/utils.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
-import 'utils.dart';
 
 main() {
   initConfig();
diff --git a/sdk/lib/_internal/pub/test/package_files_test.dart b/sdk/lib/_internal/pub/test/package_files_test.dart
index 5c61e0f..6f104bd 100644
--- a/sdk/lib/_internal/pub/test/package_files_test.dart
+++ b/sdk/lib/_internal/pub/test/package_files_test.dart
@@ -4,8 +4,6 @@
 
 library lock_file_test;
 
-import 'dart:io';
-
 import 'package:path/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
 
diff --git a/sdk/lib/_internal/pub/test/pub_cache_test.dart b/sdk/lib/_internal/pub/test/pub_cache_test.dart
index 9e790d7..39bb79b 100644
--- a/sdk/lib/_internal/pub/test/pub_cache_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_cache_test.dart
@@ -4,12 +4,6 @@
 
 library pub_cache_test;
 
-import 'dart:io';
-import 'dart:json' as json;
-
-import 'package:scheduled_test/scheduled_test.dart';
-
-import '../lib/src/io.dart';
 import 'descriptor.dart' as d;
 import 'test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
index e596672..f269126 100644
--- a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import 'package:scheduled_test/scheduled_test.dart';
 
 import 'descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/pub_test.dart b/sdk/lib/_internal/pub/test/pub_test.dart
index a521491..ce4a4c5 100644
--- a/sdk/lib/_internal/pub/test/pub_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import 'package:scheduled_test/scheduled_test.dart';
 
 import 'descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/pubspec_test.dart b/sdk/lib/_internal/pub/test/pubspec_test.dart
index 45413db..47f838a 100644
--- a/sdk/lib/_internal/pub/test/pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/pubspec_test.dart
@@ -9,7 +9,6 @@
 import '../lib/src/pubspec.dart';
 import '../lib/src/source.dart';
 import '../lib/src/source_registry.dart';
-import '../lib/src/utils.dart';
 import '../lib/src/version.dart';
 import 'test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_a_dependency_is_removed_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_a_dependency_is_removed_test.dart
index 8166680..1f0ff86 100644
--- a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_a_dependency_is_removed_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_a_dependency_is_removed_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_git_url_did_not_change_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_git_url_did_not_change_test.dart
index ee92c92..d51e5e8 100644
--- a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_git_url_did_not_change_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_git_url_did_not_change_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_locked_version_matches_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_locked_version_matches_test.dart
index fd2c2ff..f7a2a77 100644
--- a/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_locked_version_matches_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/does_not_install_first_if_locked_version_matches_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_added_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_added_test.dart
index 42bcdfd..c0fde59a 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_added_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_added_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_version_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_version_changed_test.dart
index cb64373..9652259 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_version_changed_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_dependency_version_changed_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_dev_dependency_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_dev_dependency_changed_test.dart
index 5854fb6..fb5591e 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_dev_dependency_changed_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_dev_dependency_changed_test.dart
@@ -4,7 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
 import 'dart:json' as json;
 
 import '../descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_git_ref_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_ref_changed_test.dart
index a1906fd..62238db 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_git_ref_changed_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_ref_changed_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_git_url_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_url_changed_test.dart
index 844e293..1993914 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_git_url_changed_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_git_url_changed_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_no_lockfile_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_no_lockfile_test.dart
index 9988113..f5bd1dc 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_no_lockfile_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_no_lockfile_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_path_dependency_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_path_dependency_changed_test.dart
index 0380a9a..a8ea500 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_path_dependency_changed_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_path_dependency_changed_test.dart
@@ -4,9 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-import 'dart:json' as json;
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/installs_first_if_source_changed_test.dart b/sdk/lib/_internal/pub/test/serve/installs_first_if_source_changed_test.dart
index 85d0eee..d7f5c92 100644
--- a/sdk/lib/_internal/pub/test/serve/installs_first_if_source_changed_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/installs_first_if_source_changed_test.dart
@@ -4,7 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
 import 'dart:json' as json;
 
 import '../descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/serve/invalid_urls_test.dart b/sdk/lib/_internal/pub/test/serve/invalid_urls_test.dart
index bb830733..ca85352 100644
--- a/sdk/lib/_internal/pub/test/serve/invalid_urls_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/invalid_urls_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/missing_asset_test.dart b/sdk/lib/_internal/pub/test/serve/missing_asset_test.dart
new file mode 100644
index 0000000..1f69b6c
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/missing_asset_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("responds with a 404 for missing assets", () {
+    d.dir(appPath, [
+      d.appPubspec()
+    ]).create();
+
+    startPubServe();
+    requestShould404("index.html");
+    requestShould404("packages/myapp/nope.dart");
+    requestShould404("assets/myapp/nope.png");
+    requestShould404("dir/packages/myapp/nope.dart");
+    requestShould404("dir/assets/myapp/nope.png");
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/missing_dependency_file_test.dart b/sdk/lib/_internal/pub/test/serve/missing_dependency_file_test.dart
index d1c47f2..ff454ef 100644
--- a/sdk/lib/_internal/pub/test/serve/missing_dependency_file_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/missing_dependency_file_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/missing_file_test.dart b/sdk/lib/_internal/pub/test/serve/missing_file_test.dart
index cfd7d07..693ae55 100644
--- a/sdk/lib/_internal/pub/test/serve/missing_file_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/missing_file_test.dart
@@ -4,8 +4,10 @@
 
 library pub_tests;
 
-import 'dart:io';
+import 'package:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
 
+import '../../lib/src/io.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
@@ -14,10 +16,36 @@
   initConfig();
   integration("responds with a 404 for missing files", () {
     d.dir(appPath, [
-      d.appPubspec()
+      d.appPubspec(),
+      d.dir("asset", [
+        d.file("nope.png", "nope")
+      ]),
+      d.dir("lib", [
+        d.file("nope.dart", "nope")
+      ]),
+      d.dir("web", [
+        d.file("index.html", "<body>"),
+      ])
     ]).create();
 
+    // Start the server with the files present so that it creates barback
+    // assets for them.
     startPubServe();
+
+    // TODO(rnystrom): When pub serve supports file watching, we'll have to do
+    // something here to specifically disable that so that we can get barback
+    // into the inconsistent state of thinking there is an asset but where the
+    // underlying file does not exist. One option would be configure barback
+    // with an insanely long delay between polling to ensure a poll doesn't
+    // happen.
+
+    // Now delete them.
+    schedule(() {
+      deleteEntry(path.join(sandboxDir, appPath, "asset", "nope.png"));
+      deleteEntry(path.join(sandboxDir, appPath, "lib", "nope.dart"));
+      deleteEntry(path.join(sandboxDir, appPath, "web", "index.html"));
+    }, "delete files");
+
     requestShould404("index.html");
     requestShould404("packages/myapp/nope.dart");
     requestShould404("assets/myapp/nope.png");
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_app_asset_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_app_asset_test.dart
index 1f072fc..c13c901 100644
--- a/sdk/lib/_internal/pub/test/serve/serve_from_app_asset_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_app_asset_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_app_lib_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_app_lib_test.dart
index 0ddea5f..b5b8e91 100644
--- a/sdk/lib/_internal/pub/test/serve/serve_from_app_lib_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_app_lib_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_app_web_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_app_web_test.dart
index 9c0a7f5..529facb 100644
--- a/sdk/lib/_internal/pub/test/serve/serve_from_app_web_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_app_web_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_dependency_asset_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_asset_test.dart
index f30d72c..ff25e6a 100644
--- a/sdk/lib/_internal/pub/test/serve/serve_from_dependency_asset_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_asset_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/serve_from_dependency_lib_test.dart b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_lib_test.dart
index a6a9ab2..7067525 100644
--- a/sdk/lib/_internal/pub/test/serve/serve_from_dependency_lib_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/serve_from_dependency_lib_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/unknown_dependency_test.dart b/sdk/lib/_internal/pub/test/serve/unknown_dependency_test.dart
index 434a84c..2f66d14 100644
--- a/sdk/lib/_internal/pub/test/serve/unknown_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/unknown_dependency_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/serve/utils.dart b/sdk/lib/_internal/pub/test/serve/utils.dart
index e03edd0..3a08392 100644
--- a/sdk/lib/_internal/pub/test/serve/utils.dart
+++ b/sdk/lib/_internal/pub/test/serve/utils.dart
@@ -5,13 +5,11 @@
 library pub_tests;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:http/http.dart' as http;
 import 'package:scheduled_test/scheduled_process.dart';
 import 'package:scheduled_test/scheduled_test.dart';
 
-import '../descriptor.dart' as d;
 import '../test_pub.dart';
 
 /// The pub process running "pub serve".
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index 38547f5..b018be1 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -9,20 +9,16 @@
 library test_pub;
 
 import 'dart:async';
-import 'dart:collection' show Queue;
 import 'dart:io';
 import 'dart:json' as json;
 import 'dart:math';
-import 'dart:utf';
 
 import 'package:http/testing.dart';
-import 'package:oauth2/oauth2.dart' as oauth2;
 import 'package:path/path.dart' as path;
 import 'package:scheduled_test/scheduled_process.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:unittest/compact_vm_config.dart';
-import 'package:yaml/yaml.dart';
 
 import '../lib/src/entrypoint.dart';
 // TODO(rnystrom): Using "gitlib" as the prefix here is ugly, but "git" collides
@@ -33,9 +29,6 @@
 import '../lib/src/io.dart';
 import '../lib/src/log.dart' as log;
 import '../lib/src/safe_http_server.dart';
-import '../lib/src/source/git.dart';
-import '../lib/src/source/hosted.dart';
-import '../lib/src/source/path.dart';
 import '../lib/src/system_cache.dart';
 import '../lib/src/utils.dart';
 import '../lib/src/validator.dart';
diff --git a/sdk/lib/_internal/pub/test/unknown_source_test.dart b/sdk/lib/_internal/pub/test/unknown_source_test.dart
index 9d23250..cdcc1d7 100644
--- a/sdk/lib/_internal/pub/test/unknown_source_test.dart
+++ b/sdk/lib/_internal/pub/test/unknown_source_test.dart
@@ -4,7 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
 import 'dart:json' as json;
 
 import 'descriptor.dart' as d;
diff --git a/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart b/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart
index 57d0f61..82361ce 100644
--- a/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart b/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart
index 4439df3..781e06c 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart b/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart
index dd54f57..42b9239 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart b/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart
index 7fbf233..df398de 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart b/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart
index 99b417c..8cb8971 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart b/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart
index 0296802..58b4a41 100644
--- a/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart
+++ b/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart b/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart
index 006877d..c24aca8 100644
--- a/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart
+++ b/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart b/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart
index d4a3ce5..a5ed1c6 100644
--- a/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart
+++ b/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart
@@ -4,8 +4,6 @@
 
 library pub_tests;
 
-import 'dart:io';
-
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
diff --git a/sdk/lib/_internal/pub/test/validator/directory_test.dart b/sdk/lib/_internal/pub/test/validator/directory_test.dart
index dc6df99..02571acd 100644
--- a/sdk/lib/_internal/pub/test/validator/directory_test.dart
+++ b/sdk/lib/_internal/pub/test/validator/directory_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:path/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
 
 import '../../lib/src/entrypoint.dart';
diff --git a/sdk/lib/_internal/pub/test/validator/size_test.dart b/sdk/lib/_internal/pub/test/validator/size_test.dart
index 50b7375..9949280 100644
--- a/sdk/lib/_internal/pub/test/validator/size_test.dart
+++ b/sdk/lib/_internal/pub/test/validator/size_test.dart
@@ -7,8 +7,6 @@
 
 import 'package:scheduled_test/scheduled_test.dart';
 
-import '../../lib/src/entrypoint.dart';
-import '../../lib/src/validator.dart';
 import '../../lib/src/validator/size.dart';
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
diff --git a/sdk/lib/_internal/pub/test/version_solver_test.dart b/sdk/lib/_internal/pub/test/version_solver_test.dart
index 5a9e55c..d2b42b6 100644
--- a/sdk/lib/_internal/pub/test/version_solver_test.dart
+++ b/sdk/lib/_internal/pub/test/version_solver_test.dart
@@ -5,7 +5,6 @@
 library pub_update_test;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:unittest/unittest.dart';
 
@@ -17,7 +16,6 @@
 import '../lib/src/source.dart';
 import '../lib/src/source_registry.dart';
 import '../lib/src/system_cache.dart';
-import '../lib/src/utils.dart';
 import '../lib/src/version.dart';
 import '../lib/src/solver/version_solver.dart';
 import 'test_pub.dart';
diff --git a/sdk/lib/_internal/pub/test/version_test.dart b/sdk/lib/_internal/pub/test/version_test.dart
index 6210264..ee00e6e 100644
--- a/sdk/lib/_internal/pub/test/version_test.dart
+++ b/sdk/lib/_internal/pub/test/version_test.dart
@@ -6,7 +6,6 @@
 
 import 'package:unittest/unittest.dart';
 import 'test_pub.dart';
-import '../lib/src/utils.dart';
 import '../lib/src/version.dart';
 
 main() {
diff --git a/sdk/lib/convert/converter.dart b/sdk/lib/convert/converter.dart
index 5563d7c3..2bda6fe 100644
--- a/sdk/lib/convert/converter.dart
+++ b/sdk/lib/convert/converter.dart
@@ -11,6 +11,8 @@
  *
  */
 abstract class Converter<S, T> implements StreamTransformer {
+  const Converter();
+
   /**
    * Converts [input] and returns the result of the conversion.
    */
diff --git a/sdk/lib/convert/line_splitter.dart b/sdk/lib/convert/line_splitter.dart
index cc9ad94..2676c59 100644
--- a/sdk/lib/convert/line_splitter.dart
+++ b/sdk/lib/convert/line_splitter.dart
@@ -38,21 +38,23 @@
   _LineSplitterSink(this._sink);
 
   void addSlice(String chunk, int start, int end, bool isLast) {
-    if(_carry != null) {
+    if (_carry != null) {
       chunk = _carry + chunk.substring(start, end);
       start = 0;
       end = chunk.length;
       _carry = null;
     }
     _carry = _addSlice(chunk, start, end, isLast, _sink.add);
-    if(isLast) _sink.close();
+    if (isLast) _sink.close();
   }
 
   void close() {
     addSlice('', 0, 0, true);
   }
 
-  static String _addSlice(String chunk, int start, int end, bool isLast, void adder(String val)) {
+  static String _addSlice(String chunk, int start, int end, bool isLast,
+                          void adder(String val)) {
+
     int pos = start;
     while (pos < end) {
       int skip = 0;
@@ -78,7 +80,7 @@
     }
     if (pos != start) {
       var carry = chunk.substring(start, pos);
-      if(isLast) {
+      if (isLast) {
         // Add remaining
         adder(carry);
       } else {
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index 7bb8b5d..dc0ccfa 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -287,10 +287,13 @@
   /**
    * Returns a new list containing the elements from [start] to [end].
    *
+   * The result contains elements of this list with indices greater than or
+   * equal to [start] and less than [end].
+   *
    * If [end] is omitted, the [length] of `this` is used.
    *
-   * It is an error if [start] or [end] are not indices into `this`,
-   * or if [end] is before [start].
+   * It is an error if [start] is outside the range `0` .. `[length]` or if
+   * [end] is outside the range `[start]` .. `[length]`.
    */
   List<E> sublist(int start, [int end]);
 
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 643dd58..1ff5ad4 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -354,22 +354,6 @@
   @DocsEditable()
   void update() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('DOMApplicationCache.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('DOMApplicationCache.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('DOMApplicationCache.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('DOMApplicationCache.oncached')
   @DocsEditable()
   Stream<Event> get onCached => cachedEvent.forTarget(this);
@@ -2037,6 +2021,36 @@
 
 
 @DocsEditable()
+@DomName('Key')
+@Experimental() // untriaged
+class CryptoKey extends Interceptor native "Key" {
+
+  @DomName('Key.algorithm')
+  @DocsEditable()
+  @Experimental() // untriaged
+  final Algorithm algorithm;
+
+  @DomName('Key.extractable')
+  @DocsEditable()
+  @Experimental() // untriaged
+  final bool extractable;
+
+  @DomName('Key.type')
+  @DocsEditable()
+  @Experimental() // untriaged
+  final String type;
+
+  @DomName('Key.usages')
+  @DocsEditable()
+  @Experimental() // untriaged
+  final List<String> usages;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable()
 @DomName('CryptoOperation')
 @Experimental() // untriaged
 class CryptoOperation extends Interceptor native "CryptoOperation" {
@@ -9326,7 +9340,7 @@
     } else if (JS('bool', '!!#.mozMatchesSelector', this)) {
       return JS('bool', '#.mozMatchesSelector(#)', this, selectors);
     } else if (JS('bool', '!!#.msMatchesSelector', this)) {
-      return matches = JS('bool', '#.msMatchesSelector(#)', this, selectors);
+      return JS('bool', '#.msMatchesSelector(#)', this, selectors);
     } else {
       throw new UnsupportedError("Not supported on this platform");
     }
@@ -11078,22 +11092,6 @@
   @DocsEditable()
   void close() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('EventSource.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('EventSource.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('EventSource.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('EventSource.onerror')
   @DocsEditable()
   Stream<Event> get onError => errorEvent.forTarget(this);
@@ -11547,22 +11545,6 @@
   @DocsEditable()
   void readAsText(Blob blob, [String encoding]) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('FileReader.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('FileReader.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('FileReader.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('FileReader.onabort')
   @DocsEditable()
   Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
@@ -11717,22 +11699,6 @@
   @DocsEditable()
   void write(Blob data) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('FileWriter.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('FileWriter.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('FileWriter.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('FileWriter.onabort')
   @DocsEditable()
   Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
@@ -11843,22 +11809,6 @@
   @DocsEditable()
   void notifyWhenFontsReady(VoidCallback callback) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('FontLoader.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('FontLoader.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('FontLoader.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('FontLoader.onerror')
   @DocsEditable()
   Stream<Event> get onError => errorEvent.forTarget(this);
@@ -12709,10 +12659,6 @@
   @DomName('HTMLFormControlsCollection.__getter__')
   @DocsEditable()
   Node __getter__(int index) native;
-
-  @DomName('HTMLFormControlsCollection.namedItem')
-  @DocsEditable()
-  Node namedItem(String name) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -12969,8 +12915,10 @@
    * This call is used in conjunction with [open]:
    *
    *     var request = new HttpRequest();
-   *     request.open('GET', 'http://dartlang.org')
-   *     request.onLoad.listen((event) => print('Request complete'));
+   *     request.open('GET', 'http://dartlang.org');
+   *     request.onLoad.listen((event) => print(
+   *         'Request complete ${event.target.reponseText}'));
+   *     request.send();
    *
    * is the (more verbose) equivalent of
    *
@@ -13210,22 +13158,6 @@
   @DocsEditable()
   void setRequestHeader(String header, String value) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('XMLHttpRequest.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('XMLHttpRequest.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('XMLHttpRequest.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   /**
    * Event listeners to be notified when request has been aborted,
    * generally due to calling `httpRequest.abort()`.
@@ -13357,22 +13289,6 @@
   @DocsEditable()
   static const EventStreamProvider<ProgressEvent> progressEvent = const EventStreamProvider<ProgressEvent>('progress');
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('XMLHttpRequestUpload.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('XMLHttpRequestUpload.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('XMLHttpRequestUpload.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('XMLHttpRequestUpload.onabort')
   @DocsEditable()
   Stream<ProgressEvent> get onAbort => abortEvent.forTarget(this);
@@ -14507,36 +14423,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-@DocsEditable()
-@DomName('Key')
-@Experimental() // untriaged
-class Key extends Interceptor native "Key" {
-
-  @DomName('Key.algorithm')
-  @DocsEditable()
-  @Experimental() // untriaged
-  final Algorithm algorithm;
-
-  @DomName('Key.extractable')
-  @DocsEditable()
-  @Experimental() // untriaged
-  final bool extractable;
-
-  @DomName('Key.type')
-  @DocsEditable()
-  @Experimental() // untriaged
-  final String type;
-
-  @DomName('Key.usages')
-  @DocsEditable()
-  @Experimental() // untriaged
-  final List<String> usages;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
 /**
  * An event that describes user interaction with the keyboard.
  *
@@ -15017,22 +14903,6 @@
   @DomName('MediaController.unpause')
   @DocsEditable()
   void unpause() native;
-
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MediaController.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MediaController.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MediaController.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -15739,22 +15609,6 @@
   @DocsEditable()
   void update(Uint8List key) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MediaKeySession.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MediaKeySession.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MediaKeySession.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('MediaKeySession.onwebkitkeyadded')
   @DocsEditable()
   Stream<MediaKeyEvent> get onKeyAdded => keyAddedEvent.forTarget(this);
@@ -15912,22 +15766,6 @@
   @DomName('MediaSource.removeSourceBuffer')
   @DocsEditable()
   void removeSourceBuffer(SourceBuffer buffer) native;
-
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MediaSource.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MediaSource.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MediaSource.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
 }
 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -16009,22 +15847,6 @@
   @DocsEditable()
   void stop() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MediaStream.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MediaStream.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MediaStream.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('MediaStream.onaddtrack')
   @DocsEditable()
   Stream<Event> get onAddTrack => addTrackEvent.forTarget(this);
@@ -16125,22 +15947,6 @@
   @Experimental() // untriaged
   static void getSources(MediaStreamTrackSourcesCallback callback) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MediaStreamTrack.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MediaStreamTrack.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MediaStreamTrack.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('MediaStreamTrack.onended')
   @DocsEditable()
   Stream<Event> get onEnded => endedEvent.forTarget(this);
@@ -16362,22 +16168,6 @@
   @DocsEditable()
   void start() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MessagePort.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MessagePort.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MessagePort.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('MessagePort.onmessage')
   @DocsEditable()
   Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
@@ -16524,22 +16314,6 @@
   @DocsEditable()
   List<MidiOutput> outputs() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MIDIAccess.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MIDIAccess.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MIDIAccess.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('MIDIAccess.onconnect')
   @DocsEditable()
   Stream<MidiConnectionEvent> get onConnect => connectEvent.forTarget(this);
@@ -16676,22 +16450,6 @@
   @DocsEditable()
   final String version;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('MIDIPort.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('MIDIPort.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('MIDIPort.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('MIDIPort.ondisconnect')
   @DocsEditable()
   Stream<MidiConnectionEvent> get onDisconnect => disconnectEvent.forTarget(this);
@@ -17247,22 +17005,6 @@
   @Returns('NodeList')
   @Creates('NodeList')
   List<Node> getRegionsByContent(Node contentNode) native;
-
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('WebKitNamedFlow.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('WebKitNamedFlow.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('WebKitNamedFlow.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -18019,22 +17761,6 @@
   @DocsEditable()
   Node $dom_replaceChild(Node newChild, Node oldChild) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('Node.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('Node.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('Node.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -18344,22 +18070,6 @@
   @Experimental() // nonstandard
   void show() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('Notification.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('Notification.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('Notification.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('Notification.onclick')
   @DocsEditable()
   Stream<Event> get onClick => clickEvent.forTarget(this);
@@ -19920,22 +19630,6 @@
   @DocsEditable()
   void sendTypedData(TypedData data) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('RTCDataChannel.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('RTCDataChannel.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('RTCDataChannel.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('RTCDataChannel.onclose')
   @DocsEditable()
   Stream<Event> get onClose => closeEvent.forTarget(this);
@@ -20012,22 +19706,6 @@
   @DocsEditable()
   void insertDtmf(String tones, [int duration, int interToneGap]) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('RTCDTMFSender.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('RTCDTMFSender.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('RTCDTMFSender.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('RTCDTMFSender.ontonechange')
   @DocsEditable()
   Stream<RtcDtmfToneChangeEvent> get onToneChange => toneChangeEvent.forTarget(this);
@@ -20378,22 +20056,6 @@
   @DocsEditable()
   void _updateIce_3() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('RTCPeerConnection.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('RTCPeerConnection.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('RTCPeerConnection.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('RTCPeerConnection.onaddstream')
   @DocsEditable()
   Stream<MediaStreamEvent> get onAddStream => addStreamEvent.forTarget(this);
@@ -21155,25 +20817,6 @@
   @DocsEditable()
   @Experimental() // untriaged
   void appendBufferView(TypedData data) native;
-
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('SourceBuffer.addEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('SourceBuffer.dispatchEvent')
-  @DocsEditable()
-  @Experimental() // untriaged
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('SourceBuffer.removeEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -21239,22 +20882,6 @@
   @DomName('SourceBufferList.item')
   @DocsEditable()
   SourceBuffer item(int index) native;
-
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('SourceBufferList.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('SourceBufferList.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('SourceBufferList.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -21562,22 +21189,6 @@
   @DocsEditable()
   void stop() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('SpeechRecognition.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('SpeechRecognition.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('SpeechRecognition.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('SpeechRecognition.onaudioend')
   @DocsEditable()
   Stream<Event> get onAudioEnd => audioEndEvent.forTarget(this);
@@ -21869,25 +21480,6 @@
   @DocsEditable()
   num volume;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('SpeechSynthesisUtterance.addEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('SpeechSynthesisUtterance.dispatchEvent')
-  @DocsEditable()
-  @Experimental() // untriaged
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('SpeechSynthesisUtterance.removeEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('SpeechSynthesisUtterance.onboundary')
   @DocsEditable()
   Stream<SpeechSynthesisEvent> get onBoundary => boundaryEvent.forTarget(this);
@@ -23255,22 +22847,6 @@
   @DocsEditable()
   void removeCue(TextTrackCue cue) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('TextTrack.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('TextTrack.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('TextTrack.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('TextTrack.oncuechange')
   @DocsEditable()
   Stream<Event> get onCueChange => cueChangeEvent.forTarget(this);
@@ -23364,22 +22940,6 @@
   @Experimental() // nonstandard
   DocumentFragment getCueAsHtml() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('TextTrackCue.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('TextTrackCue.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('TextTrackCue.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('TextTrackCue.onenter')
   @DocsEditable()
   Stream<Event> get onEnter => enterEvent.forTarget(this);
@@ -23524,22 +23084,6 @@
   @DocsEditable()
   TextTrack item(int index) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('TextTrackList.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('TextTrackList.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('TextTrackList.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('TextTrackList.onaddtrack')
   @DocsEditable()
   Stream<TrackEvent> get onAddTrack => addTrackEvent.forTarget(this);
@@ -24537,22 +24081,6 @@
   @DocsEditable()
   void sendTypedData(TypedData data) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('WebSocket.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('WebSocket.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('WebSocket.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('WebSocket.onclose')
   @DocsEditable()
   Stream<CloseEvent> get onClose => closeEvent.forTarget(this);
@@ -25694,22 +25222,6 @@
     return completer.future;
   }
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('Window.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('Window.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('Window.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   // From WindowBase64
 
   @DomName('Window.atob')
@@ -26131,25 +25643,6 @@
   @DocsEditable()
   void terminate() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('Worker.addEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('Worker.dispatchEvent')
-  @DocsEditable()
-  @Experimental() // untriaged
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('Worker.removeEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('Worker.onerror')
   @DocsEditable()
   @Experimental() // untriaged
@@ -26316,25 +25809,6 @@
     return completer.future;
   }
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('WorkerGlobalScope.addEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('WorkerGlobalScope.dispatchEvent')
-  @DocsEditable()
-  @Experimental() // untriaged
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('WorkerGlobalScope.removeEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   // From WindowBase64
 
   @DomName('WorkerGlobalScope.atob')
@@ -27591,8 +27065,6 @@
   }
   static _SharedWorker _create_1(scriptURL, name) => JS('_SharedWorker', 'new SharedWorker(#,#)', scriptURL, name);
   static _SharedWorker _create_2(scriptURL) => JS('_SharedWorker', 'new SharedWorker(#)', scriptURL);
-
-  // From EventTarget
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -27803,8 +27275,6 @@
     return _WebKitMediaSource._create_1();
   }
   static _WebKitMediaSource _create_1() => JS('_WebKitMediaSource', 'new WebKitMediaSource()');
-
-  // From EventTarget
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -27833,8 +27303,6 @@
   @DocsEditable()
   @Experimental() // untriaged
   _WebKitSourceBuffer _item(int index) native;
-
-  // From EventTarget
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -29478,7 +28946,7 @@
         !_firesKeyPressEvent(event)) {
       // Some browsers have quirks not firing keypress events where all other
       // browsers do. This makes them more consistent.
-      processKeyPress(event);
+      processKeyPress(e);
     }
     _keyDownList.add(event);
     _dispatch(event);
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 9e93000..843ea2c 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -2416,6 +2416,39 @@
 
 
 @DocsEditable()
+@DomName('Key')
+@Experimental() // untriaged
+class CryptoKey extends NativeFieldWrapperClass1 {
+
+  @DomName('Key.algorithm')
+  @DocsEditable()
+  @Experimental() // untriaged
+  Algorithm get algorithm native "Key_algorithm_Getter";
+
+  @DomName('Key.extractable')
+  @DocsEditable()
+  @Experimental() // untriaged
+  bool get extractable native "Key_extractable_Getter";
+
+  @DomName('Key.type')
+  @DocsEditable()
+  @Experimental() // untriaged
+  String get type native "Key_type_Getter";
+
+  @DomName('Key.usages')
+  @DocsEditable()
+  @Experimental() // untriaged
+  List<String> get usages native "Key_usages_Getter";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable()
 @DomName('CryptoOperation')
 @Experimental() // untriaged
 class CryptoOperation extends NativeFieldWrapperClass1 {
@@ -13422,8 +13455,10 @@
    * This call is used in conjunction with [open]:
    *
    *     var request = new HttpRequest();
-   *     request.open('GET', 'http://dartlang.org')
-   *     request.onLoad.listen((event) => print('Request complete'));
+   *     request.open('GET', 'http://dartlang.org');
+   *     request.onLoad.listen((event) => print(
+   *         'Request complete ${event.target.reponseText}'));
+   *     request.send();
    *
    * is the (more verbose) equivalent of
    *
@@ -15269,39 +15304,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable()
-@DomName('Key')
-@Experimental() // untriaged
-class Key extends NativeFieldWrapperClass1 {
-
-  @DomName('Key.algorithm')
-  @DocsEditable()
-  @Experimental() // untriaged
-  Algorithm get algorithm native "Key_algorithm_Getter";
-
-  @DomName('Key.extractable')
-  @DocsEditable()
-  @Experimental() // untriaged
-  bool get extractable native "Key_extractable_Getter";
-
-  @DomName('Key.type')
-  @DocsEditable()
-  @Experimental() // untriaged
-  String get type native "Key_type_Getter";
-
-  @DomName('Key.usages')
-  @DocsEditable()
-  @Experimental() // untriaged
-  List<String> get usages native "Key_usages_Getter";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
 
 @DomName('KeyboardEvent')
 class KeyboardEvent extends UIEvent {
@@ -25722,13 +25724,13 @@
     if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_1(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
+    if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_2(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
+    if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_3(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
+    if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_4(blob_OR_source_OR_stream);
     }
     throw new ArgumentError("Incorrect number or type of arguments");
@@ -31030,7 +31032,7 @@
         !_firesKeyPressEvent(event)) {
       // Some browsers have quirks not firing keypress events where all other
       // browsers do. This makes them more consistent.
-      processKeyPress(event);
+      processKeyPress(e);
     }
     _keyDownList.add(event);
     _dispatch(event);
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 9304548..8296329 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -361,22 +361,6 @@
   @DocsEditable()
   void deleteObjectStore(String name) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('IDBDatabase.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('IDBDatabase.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('IDBDatabase.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('IDBDatabase.onabort')
   @DocsEditable()
   Stream<Event> get onAbort => abortEvent.forTarget(this);
@@ -1163,22 +1147,6 @@
   @DocsEditable()
   final Transaction transaction;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('IDBRequest.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('IDBRequest.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('IDBRequest.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('IDBRequest.onerror')
   @DocsEditable()
   Stream<Event> get onError => errorEvent.forTarget(this);
@@ -1256,22 +1224,6 @@
   @DocsEditable()
   ObjectStore objectStore(String name) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('IDBTransaction.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('IDBTransaction.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('IDBTransaction.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('IDBTransaction.onabort')
   @DocsEditable()
   Stream<Event> get onAbort => abortEvent.forTarget(this);
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 17d67be..e27b610 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -98,7 +98,7 @@
   }
 
   Future<Directory> createRecursively() {
-    var path = new Path(path);
+    var path = new Path(this.path);
     var dirsToCreate = [];
     var terminator = path.isAbsolute ? '/' : '';
     while (path.toString() != terminator) {
@@ -139,7 +139,7 @@
   }
 
   void createRecursivelySync() {
-    var path = new Path(path);
+    var path = new Path(this.path);
     var dirsToCreate = [];
     var terminator = path.isAbsolute ? '/' : '';
     while (path.toString() != terminator) {
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index b6a47c79..cf9a7ef 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -346,7 +346,7 @@
   }
 
   Directory get directory {
-    Path path = new Path(path).directoryPath;
+    Path path = new Path(this.path).directoryPath;
     return new Directory.fromPath(path);
   }
 
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 4b490c2..1433ac8 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -142,10 +142,10 @@
    * value of [:0:] (the default) a reasonable value will be chosen by
    * the system.
    *
-   * The certificate with Distinguished Name [certificateName] is looked
-   * up in the certificate database, and is used as the server certificate.
-   * if [requestClientCertificate] is true, the server will request clients
-   * to authenticate with a client certificate.
+   * The certificate with nickname or distinguished name (DN) [certificateName]
+   * is looked up in the certificate database, and is used as the server
+   * certificate. If [requestClientCertificate] is true, the server will
+   * request clients to authenticate with a client certificate.
    */
 
   static Future<HttpServer> bindSecure(address,
@@ -1172,6 +1172,32 @@
                            HttpClientCredentials credentials);
 
   /**
+   * Sets a callback that will decide whether to accept a secure connection
+   * with a server certificate that cannot be authenticated by any of our
+   * trusted root certificates.
+   *
+   * When an secure HTTP request if made, using this HttpClient, and the
+   * server returns a server certificate that cannot be authenticated, the
+   * callback is called asynchronously with the [X509Certificate] object and
+   * the server's hostname and port.  If the value of [badCertificateCallback]
+   * is [null], the bad certificate is rejected, as if the callback
+   * returned [false]
+   *
+   * If the callback returns true, the secure connection is accepted and the
+   * [:Future<HttpClientRequest>:] that was returned from the call making the
+   * request completes with a valid HttpRequest object. If the callback returns
+   * false, the [:Future<HttpClientRequest>:] completes with an exception.
+   *
+   * If a bad certificate is received on a connection attempt, the library calls
+   * the function that was the value of badCertificateCallback at the time
+   * the the request is made, even if the value of badCertificateCallback
+   * has changed since then.
+   */
+  set badCertificateCallback(bool callback(X509Certificate cert,
+                                           String host,
+                                           int port));
+
+  /**
    * Shutdown the HTTP client. If [force] is [:false:] (the default)
    * the [:HttpClient:] will be kept alive until all active
    * connections are done. If [force] is [:true:] any active
@@ -1314,8 +1340,8 @@
   String get reasonPhrase;
 
   /**
-   * Returns the content length of the request body. Returns -1 if the size of
-   * the request body is not known in advance.
+   * Returns the content length of the response body. Returns -1 if the size of
+   * the response body is not known in advance.
    */
   int get contentLength;
 
@@ -1489,4 +1515,6 @@
                           List<RedirectInfo> this.redirects);
 
   String toString() => "RedirectException: $message";
+
+  Uri get uri => redirects.last.location;
 }
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index ca097c9..1a5e3a5 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -1335,7 +1335,7 @@
         .then((_) => _socket.destroy());
   }
 
-  Future<_HttpClientConnection> createProxyTunnel(host, port, proxy) {
+  Future<_HttpClientConnection> createProxyTunnel(host, port, proxy, callback) {
     _HttpClientRequest request =
         send(new Uri(host: host, port: port),
              port,
@@ -1355,7 +1355,8 @@
                   "(${response.statusCode} ${response.reasonPhrase})";
           }
           var socket = response._httpRequest._httpClientConnection._socket;
-          return SecureSocket.secure(socket, host: host);
+          return SecureSocket.secure(
+              socket, host: host, onBadCertificate: callback);
         })
         .then((secureSocket) {
           String key = _HttpClientConnection.makeKey(true, host, port);
@@ -1409,6 +1410,7 @@
   Function _authenticateProxy;
   Function _findProxy = HttpClient.findProxyFromEnvironment;
   Duration _idleTimeout = const Duration(seconds: 15);
+  Function _badCertificateCallback;
 
   Timer _noActiveTimer;
 
@@ -1426,6 +1428,12 @@
         }));
   }
 
+  set badCertificateCallback(bool callback(X509Certificate cert,
+                                           String host,
+                                           int port)) {
+    _badCertificateCallback = callback;
+  }
+
 
   Future<HttpClientRequest> open(String method,
                                  String host,
@@ -1674,17 +1682,23 @@
         _updateTimers();
         return new Future.value(new _ConnnectionInfo(connection, proxy));
       }
+      var currentBadCertificateCallback = _badCertificateCallback;
+      bool callback(X509Certificate certificate) =>
+          currentBadCertificateCallback == null ? false :
+          currentBadCertificateCallback(certificate, uriHost, uriPort);
       return (isSecure && proxy.isDirect
                   ? SecureSocket.connect(host,
                                          port,
-                                         sendClientCertificate: true)
+                                         sendClientCertificate: true,
+                                         onBadCertificate: callback)
                   : Socket.connect(host, port))
         .then((socket) {
           socket.setOption(SocketOption.TCP_NODELAY, true);
           var connection = new _HttpClientConnection(key, socket, this);
           if (isSecure && !proxy.isDirect) {
             connection._dispose = true;
-            return connection.createProxyTunnel(uriHost, uriPort, proxy)
+            return connection.createProxyTunnel(
+                uriHost, uriPort, proxy, callback)
                 .then((tunnel) {
                   _activeConnections.add(tunnel);
                   return new _ConnnectionInfo(tunnel, proxy);
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 8c28eb4..8b726ed 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -55,14 +55,20 @@
    * Synchronously updates the link. Calling [updateSync] on a non-existing link
    * will throw an exception.
    *
-   * If [linkRelative] is true, the target argument should be a relative path,
-   * and the link will interpret the target as a path relative to the link's
-   * directory.
+   * On the Windows platform, this will only work with directories, and the
+   * target directory must exist.
+   */
+  void updateSync(String target);
+
+  /**
+   * Updates the link. Returns a [:Future<Link>:] that completes with the
+   * link when it has been updated.  Calling [update] on a non-existing link
+   * will complete its returned future with an exception.
    *
    * On the Windows platform, this will only work with directories, and the
    * target directory must exist.
    */
-  void updateSync(String target, {bool linkRelative: false });
+  Future<Link> update(String target);
 
   /**
    * Deletes the link. Returns a [:Future<Link>:] that completes with
@@ -198,12 +204,23 @@
     return target;
   }
 
-  void updateSync(String target, {bool linkRelative: false }) {
-    // TODO(whesse): Replace with atomic update, where supported by platform.
+  void updateSync(String target) {
+    // TODO(12414): Replace with atomic update, where supported by platform.
+    // Atomically changing a link can be done by creating the new link, with
+    // a different name, and using the rename() posix call to move it to
+    // the old name atomically.
     deleteSync();
     createSync(target);
   }
 
+  Future<Link> update(String target) {
+    // TODO(12414): Replace with atomic update, where supported by platform.
+    // Atomically changing a link can be done by creating the new link, with
+    // a different name, and using the rename() posix call to move it to
+    // the old name atomically.
+    return delete().then((_) => create(target));
+  }
+
   Future<Link> delete() {
     _ensureFileService();
     List request = new List(2);
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 78c13a8..0f89a30 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -147,6 +147,26 @@
        Encoding stdoutEncoding: Encoding.SYSTEM,
        Encoding stderrEncoding: Encoding.SYSTEM});
 
+
+  /**
+   * Starts a process and runs it to completion. This is a synchronous
+   * call and will block until the child process terminates.
+   *
+   * The arguments are the same as for `Process.run`.
+   *
+   * Returns a `ProcessResult` with the result of running the process,
+   * i.e., exit code, standard out and standard in.
+   */
+  external static ProcessResult runSync(
+      String executable,
+      List<String> arguments,
+      {String workingDirectory,
+       Map<String, String> environment,
+       bool includeParentEnvironment: true,
+       bool runInShell: false,
+       Encoding stdoutEncoding: Encoding.SYSTEM,
+       Encoding stderrEncoding: Encoding.SYSTEM});
+
   /**
    * Returns the standard output stream of the process as a [:Stream:].
    *
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 2fd9659..f2a33e2 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -96,7 +96,6 @@
     return completer.future;
   }
 
-
   /**
    * Takes an already connected [socket] and starts server side TLS
    * handshake to make the communication secure. When the returned
@@ -205,23 +204,29 @@
    */
   external static void initialize({String database,
                                    String password,
-                                   bool useBuiltinRoots: true});
-
+                                   bool useBuiltinRoots: true,
+                                   bool readOnly: true});
 
   /**
-   * Trust strings for use in [addCertificate].
+   * Trust strings for use in [addCertificate] and [changeTrust].
    */
   static const String TRUST_ISSUE_SERVER_CERTIFICATES = 'C,,';
   static const String TRUST_ISSUE_CLIENT_CERTIFICATES = 'T,,';
   static const String TRUST_ISSUE_CLIENT_SERVER_CERTIFICATES = 'TC,,';
   static const String TRUST_CERTIFICATE = 'P,,';
 
-
   /**
    * Adds a X509 certificate (for SSL and TLS secure networking) to the
-   * in-memory certificate database.  Returns an X509Certificate object
+   * in-memory certificate cache.  Returns an X509Certificate object
    * with information about the added certificate.
    *
+   * The in-memory certificate cache is different from the certificate
+   * database opened by `SecureSocket.initialize`, and certificates added
+   * by [addCertificate] cannot be modified or removed by [changeTrust]
+   * or [removeCertificate].  However, if the certificate is already in the
+   * database, then [removeCertificate] will remove it from both the database
+   * and the in-memory cache.
+   *
    * [certificate] must be a list of bytes encoding a certificate in
    *  PEM format: a base64 encoded DER certificate, enclosed between
    * "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----".
@@ -240,6 +245,76 @@
    */
   external static X509Certificate addCertificate(List<int> certificate,
                                                  String trust);
+
+  /**
+   * Adds a X509 certificates (for SSL and TLS secure networking) with
+   * their private keys to the certificate database.  SecureSocket.initialize
+   * must have been called with the path to a certificate database, and with
+   * readOnly set to `false`.
+   *
+   * [certificates] must be a list containing the bytes of a PKCS #12 encoded
+   * list of certificates and private keys.  These are commonly called
+   * `.pfx` or `.p12` files.  Only PKCS #12 files using
+   * 3-key triple-DES and 40 bit RC2 encryption are accepted.
+   *
+   * All certificates are imported with no default trust, and the appropriate
+   * uses of each certificate must be added with `SecureSocket.changeTrust`.
+   *
+   * See the documentation of NSS certutil at
+   * http://developer.mozilla.org/en-US/docs/NSS_reference/NSS_tools_:_certutil
+   * or
+   * http://blogs.oracle.com/meena/entry/notes_about_trust_flags
+   * for more information about trust attributes.
+   *
+   * Returns a CertificateError if it fails. The error code -8183 does not
+   * indicate that the PKCS #12 file is corrupt.  It also is returned if
+   * the certificate database is read-only, or is the default internal database,
+   * or if the password for the file or database is incorrect.
+   */
+  external static importCertificatesWithPrivateKeys(List<int> certificates,
+                                                    String password);
+
+  /**
+   * Changes the trust settings for the certificate with nickname [nickname].
+   * This certificate must exist in the certificate database.
+   * SecureSocket.initialize must have been called with the path to a
+   * certificate database, and with readOnly set to false.
+   *
+   * [trust] is a string specifying the allowed uses of this certificate.
+   * For example, 'TC,,' specifies that the certificate is for a certificate
+   * authority that is trusted to issue server and client certificates, so
+   * that a server or client certificate signed by this authority will be
+   * accepted.
+   *
+   * See the documentation of NSS certutil at
+   * http://developer.mozilla.org/en-US/docs/NSS_reference/NSS_tools_:_certutil
+   * or
+   * http://blogs.oracle.com/meena/entry/notes_about_trust_flags
+   * for more information about trust attributes.
+   */
+  external static X509Certificate changeTrust(String nickname,
+                                              String trust);
+
+  /**
+   * Gets the certificate with nickname [nickname] from
+   * the certificate database.  Returns an X509Certificate object with
+   * information about the certificate.
+   *
+   * Throws a CertificateException if it cannot find the certificate with
+   * the given nickname.
+   */
+  external static X509Certificate getCertificate(String nickname);
+
+  /**
+   * Removes the certificate with nickname [nickname] permanently from
+   * the certificate database.
+   * This certificate must exist in the certificate database.
+   * SecureSocket.initialize must have been called with the path to a
+   * certificate database, and with readOnly set to false.
+   *
+   * Returns null if it cannot find the certificate with that nickname.
+   */
+  external static removeCertificate(String nickname);
 }
 
 
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 140bd3b..aec2919 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -826,7 +826,7 @@
                                      cancelOnError: cancelOnError);
   }
 
-  Duration get pingnterval => _pingInterval;
+  Duration get pingInterval => _pingInterval;
 
   void set pingInterval(Duration interval) {
     if (_writeClosed) return;
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 359a71c..ac40dc1 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -848,25 +848,6 @@
   @DocsEditable()
   final ElementInstance previousSibling;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('SVGElementInstance.addEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('SVGElementInstance.dispatchEvent')
-  @DocsEditable()
-  @Experimental() // untriaged
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('SVGElementInstance.removeEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('SVGElementInstance.onabort')
   @DocsEditable()
   Stream<Event> get onAbort => abortEvent.forTarget(this);
@@ -4759,11 +4740,6 @@
   @DomName('SVGDocument.rootElement')
   @DocsEditable()
   final SvgSvgElement rootElement;
-
-  @JSName('createEvent')
-  @DomName('SVGDocument.createEvent')
-  @DocsEditable()
-  Event $dom_createEvent(String eventType) native;
 }
 // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index b3355ed..d69253a1 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -357,25 +357,6 @@
   @DocsEditable()
   void startRendering() native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('AudioContext.addEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('AudioContext.dispatchEvent')
-  @DocsEditable()
-  @Experimental() // untriaged
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('AudioContext.removeEventListener')
-  @DocsEditable()
-  @Experimental() // untriaged
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('AudioContext.oncomplete')
   @DocsEditable()
   Stream<Event> get onComplete => completeEvent.forTarget(this);
@@ -500,22 +481,6 @@
   @DocsEditable()
   void disconnect(int output) native;
 
-  // From EventTarget
-
-  @JSName('addEventListener')
-  @DomName('AudioNode.addEventListener')
-  @DocsEditable()
-  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
-
-  @DomName('AudioNode.dispatchEvent')
-  @DocsEditable()
-  bool dispatchEvent(Event event) native;
-
-  @JSName('removeEventListener')
-  @DomName('AudioNode.removeEventListener')
-  @DocsEditable()
-  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
-
   @DomName('AudioNode.connect')
   void connectNode(AudioNode destination, [int output = 0, int input = 0]) =>
       $dom_connect(destination, output, input);
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index a79a085..a7f309b 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -405,11 +405,7 @@
 Language/11_Expressions/11_Instance_Creation/1_New_A01_t04: fail, OK
 
 # co19 issue #455, undeclared identifier is static warning
-Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t10: fail, OK
-Language/12_Statements/04_Local_Function_Declaration_A02_t02: fail, OK
-Language/13_Libraries_and_Scripts/1_Imports_A02_t12: fail, OK
 Language/13_Libraries_and_Scripts/1_Imports_A02_t14: fail, OK
-Language/13_Libraries_and_Scripts/1_Imports_A02_t15: fail, OK
 
 # co19 issue #456
 Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t04: fail, OK
@@ -455,3 +451,26 @@
 
 # co19 issue 483, instance access to static member
 Language/11_Expressions/15_Method_Invocation/2_Cascaded_Invocation_A01_t19: fail, OK
+
+# co19 issue #486, some override errors are now warnings
+Language/07_Classes/1_Instance_Methods_A01_t01: fail, OK
+Language/07_Classes/1_Instance_Methods_A01_t02: fail, OK
+Language/07_Classes/1_Instance_Methods_A01_t03: fail, OK
+Language/07_Classes/1_Instance_Methods_A01_t04: fail, OK
+Language/07_Classes/1_Instance_Methods_A01_t05: fail, OK
+Language/07_Classes/1_Instance_Methods_A01_t06: fail, OK
+Language/07_Classes/1_Instance_Methods_A02_t02: fail, OK
+Language/07_Classes/1_Instance_Methods_A02_t05: fail, OK
+Language/07_Classes/1_Instance_Methods_A06_t01: fail, OK
+Language/07_Classes/1_Instance_Methods_A06_t02: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A03_t01: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A03_t02: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A03_t03: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A03_t04: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A03_t05: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A04_t01: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A04_t05: fail, OK
+Language/07_Classes/4_Abstract_Instance_Members_A04_t06: fail, OK
+
+# co19 issue #487, Function type T may be assigned to function type T iff T <: S
+Language/14_Types/5_Function_Types_A01_t01: fail, OK
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 4e93a27..94e2291 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -14,6 +14,7 @@
 
 [ $runtime == vm && $system == windows ]
 LibTest/core/Stopwatch/elapsed_A01_t01: Pass, Fail # Issue 11382.
+LibTest/core/Stopwatch/elapsed_A01_t03: Pass, Fail # Issue 12383.
 
 [ $runtime == vm ]
 Language/11_Expressions/33_Argument_Definition_Test_A02_t02: Crash, Pass # Issue 9597 (question-mark operator)
@@ -388,9 +389,18 @@
 LibTest/core/FallThroughError/toString_A01_t01: Fail # FallThroughError is no longer const. Issue 459
 LibTest/core/FallThroughError/FallThroughError_A01_t01: Fail # FallThroughError is no longer const. Issue 459
 
-Language/07_Classes/4_Abstract_Instance_Members_A04_t01: Fail # Override rules have been relaxed. Issue
-Language/07_Classes/1_Instance_Methods_A02_t02: Fail # Override rules have been relaxed. Issue
-Language/07_Classes/1_Instance_Methods_A02_t05: Fail # Override rules have been relaxed. Issue
+Language/07_Classes/1_Instance_Methods_A01_t01: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A01_t02: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A01_t03: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A01_t04: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A01_t05: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A01_t06: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A02_t02: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A02_t05: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A06_t01: Fail # Issue 485
+Language/07_Classes/1_Instance_Methods_A06_t02: Fail # Issue 485
+Language/07_Classes/4_Abstract_Instance_Members_A03_t01: Fail # Issue 485
+Language/07_Classes/4_Abstract_Instance_Members_A04_t01: Fail # Issue 485
 
 Language/03_Overview/1_Scoping_A02_t28: Fail # Issue 463
 Language/03_Overview/2_Privacy_A01_t06: Fail # Issue 463
@@ -534,7 +544,11 @@
 LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
 
 [ $compiler == none && $runtime == vm && $arch == mips ]
-*: Skip
+LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
+LibTest/math/log_A01_t01: Fail
+LibTest/math/asin_A01_t01: Fail
+LibTest/math/acos_A01_t01: Fail
+LibTest/core/double/toInt_A01_t01: Fail
 
 [ $compiler == none && $runtime == vm && $arch == simmips ]
 LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
diff --git a/tests/compiler/dart2js/minify_many_locals_test.dart b/tests/compiler/dart2js/minify_many_locals_test.dart
index 5252816..1d62fa4 100644
--- a/tests/compiler/dart2js/minify_many_locals_test.dart
+++ b/tests/compiler/dart2js/minify_many_locals_test.dart
@@ -21,21 +21,21 @@
   RegExp re = new RegExp(r"\(a,b,c");
   Expect.isTrue(re.hasMatch(generated));
 
-  re = new RegExp(r"x,y,z,A,B,C");
+  re = new RegExp(r"x,y,z,a0,a1,a2");
   Expect.isTrue(re.hasMatch(generated));
-  
-  re = new RegExp(r"Y,Z,a0,a1,a2,a3,a4,a5,a6");
+
+  re = new RegExp(r"y,z,a0,a1,a2,a3,a4,a5,a6");
   Expect.isTrue(re.hasMatch(generated));
 
   re = new RegExp(r"g8,g9,h0,h1");
   Expect.isTrue(re.hasMatch(generated));
 
-  re = new RegExp(r"Z8,Z9,aa0,aa1,aa2");
+  re = new RegExp(r"z8,z9,aa0,aa1,aa2");
   Expect.isTrue(re.hasMatch(generated));
 
   re = new RegExp(r"aa9,ab0,ab1");
   Expect.isTrue(re.hasMatch(generated));
 
-  re = new RegExp(r"aZ9,ba0,ba1");
+  re = new RegExp(r"az9,ba0,ba1");
   Expect.isTrue(re.hasMatch(generated));
 }
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 75623b9..2608a31 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -15,7 +15,9 @@
     Compiler;
 
 import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart' show
-    SourceString;
+    Constant,
+    SourceString,
+    TypeConstant;
 
 import
     '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart'
@@ -48,7 +50,7 @@
   // 2. Some code was refactored, and there are more methods.
   // Either situation could be problematic, but in situation 2, it is often
   // acceptable to increase [expectedMethodCount] a little.
-  int expectedMethodCount = 317;
+  int expectedMethodCount = 322;
   Expect.isTrue(
       generatedCode.length <= expectedMethodCount,
       'Too many compiled methods: '
@@ -84,6 +86,36 @@
       }
     });
   }
+
+  // There should at least be three metadata constants:
+  // 1. The type literal 'Foo'.
+  // 2. The list 'const [Foo]'.
+  // 3. The constructed constant for 'MirrorsUsed'.
+  Expect.isTrue(compiler.metadataHandler.compiledConstants.length >= 3);
+
+  // Make sure that most of the metadata constants aren't included in the
+  // generated code.
+  for (Constant constant in compiler.metadataHandler.compiledConstants) {
+    if (constant is TypeConstant && '${constant.representedType}' == 'Foo') {
+      // The type literal 'Foo' is retained as a constant because it is being
+      // passed to reflectClass.
+      continue;
+    }
+    Expect.isFalse(
+        compiler.constantHandler.compiledConstants.contains(constant),
+        '$constant');
+  }
+
+  // The type literal 'Foo' is both used as metadata, and as a plain value in
+  // the program. Make sure that it isn't duplicated.
+  int fooConstantCount = 0;
+  for (Constant constant in compiler.metadataHandler.compiledConstants) {
+    if (constant is TypeConstant && '${constant.representedType}' == 'Foo') {
+      fooConstantCount++;
+    }
+  }
+  Expect.equals(
+      1, fooConstantCount, "The type literal 'Foo' is duplicated or missing.");
 }
 
 const MEMORY_SOURCE_FILES = const <String, String> {
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index fc6fe0a..b62a220 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -296,13 +296,20 @@
 }
 
 testSwitch4() {
-  switch(topLevelGetter) {
+  switch (topLevelGetter) {
     case 1: break;
     default: break;
   }
   return 42;
 }
 
+testSwitch5() {
+  switch (topLevelGetter) {
+    case 1: return 1;
+    default: return 2;
+  }
+}
+
 testContinue1() {
   var a = 42;
   var b;
@@ -364,6 +371,43 @@
   return testReturnItselfOrInt(a);
 }
 
+testDoWhile1() {
+  var a = 42;
+  do {
+    a = 'foo';
+  } while (true);
+  return a;
+}
+
+testDoWhile2() {
+  var a = 42;
+  do {
+    a = 'foo';
+    return;
+  } while (true);
+  return a;
+}
+
+testDoWhile3() {
+  var a = 42;
+  do {
+    a = 'foo';
+    if (true) continue;
+    return 42;
+  } while (true);
+  return a;
+}
+
+testDoWhile4() {
+  var a = 'foo';
+  do {
+    a = 54;
+    if (true) break;
+    return 3.5;
+  } while (true);
+  return a;
+}
+
 testReturnInvokeDynamicGetter() => new A().myFactory();
 
 var topLevelConstList = const [42];
@@ -404,6 +448,22 @@
   returnInt9() => super.myField;
 }
 
+testCascade1() {
+  return [1, 2, 3]..add(4)..add(5);
+}
+
+testCascade2() {
+  return new CascadeHelper()
+      ..a = "hello"
+      ..b = 42
+      ..i += 1;
+}
+
+class CascadeHelper {
+  var a, b;
+  var i = 0;
+}
+
 main() {
   // Ensure a function class is being instantiated.
   () => 42;
@@ -453,10 +513,15 @@
   testSwitch2();
   testSwitch3();
   testSwitch4();
+  testSwitch5();
   testContinue1();
   testBreak1();
   testContinue2();
   testBreak2();
+  testDoWhile1();
+  testDoWhile2();
+  testDoWhile3();
+  testDoWhile4();
   new A() == null;
   new A()..returnInt1()
          ..returnInt2()
@@ -478,6 +543,8 @@
   testReturnElementOfConstList2();
   testReturnItselfOrInt(topLevelGetter());
   testReturnInvokeDynamicGetter();
+  testCascade1();
+  testCascade2();
 }
 """;
 
@@ -547,6 +614,7 @@
   checkReturn('testSwitch2', typesTask.intType);
   checkReturn('testSwitch3', interceptorType.nullable());
   checkReturn('testSwitch4', typesTask.intType);
+  checkReturn('testSwitch5', typesTask.intType);
   checkReturn('testContinue1', interceptorType.nullable());
   checkReturn('testBreak1', interceptorType.nullable());
   checkReturn('testContinue2', interceptorType.nullable());
@@ -556,6 +624,11 @@
   checkReturn('testReturnItselfOrInt', typesTask.intType);
   checkReturn('testReturnInvokeDynamicGetter', typesTask.dynamicType);
 
+  checkReturn('testDoWhile1', typesTask.stringType);
+  checkReturn('testDoWhile2', typesTask.nullType);
+  checkReturn('testDoWhile3', interceptorType);
+  checkReturn('testDoWhile4', typesTask.numType);
+
   checkReturnInClass(String className, String methodName, type) {
     var cls = findElement(compiler, className);
     var element = cls.lookupLocalMember(buildSourceString(methodName));
@@ -588,4 +661,8 @@
                   typesInferrer.getReturnTypeOfElement(element));
   }
   checkFactoryConstructor('A', '');
+
+  checkReturn('testCascade1', typesTask.growableListType);
+  checkReturn('testCascade2', new TypeMask.nonNullExact(
+      typesTask.rawTypeOf(findElement(compiler, 'CascadeHelper'))));
 }
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index e67a374..d2fd801 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -20,7 +20,6 @@
 
 [ $compiler == none || $compiler == dart2dart ]
 symbol_test/none: Fail # bug 11669
-error_stack_trace_test: Fail  # Bug http://dartbug.com/11680
 error_stack_trace2_test: Fail  # Bug 5802
 
 [ $runtime == ff || $runtime == ie9 || $runtime == jsshell ]
@@ -53,6 +52,7 @@
 string_trim_unicode_test: Fail  # Bug 6569
 
 [ $compiler == dart2js ]
+error_stack_trace1_test: Fail # Issue 12399
 math_parse_double_test: Fail # Expect.equals(expected: <78187493520>, actual: <0>)
 math_test: Fail # issue 3333
 surrogate_pair_toUpper_test: Fail # Issue 6707
@@ -63,9 +63,6 @@
 
 string_replace_func_test: Skip # Bug 6554 - doesn't terminate.
 
-error_stack_trace_test: Fail  # Bug http://dartbug.com/11681
-error_stack_trace2_test: Fail  # Bug http://dartbug.com/11681
-
 [ $compiler == dart2js && $runtime == none ]
 *: Fail, Pass # TODO(ahe): Triage these tests.
 
@@ -95,6 +92,9 @@
 iterable_to_list_test: Fail
 iterable_to_set_test: Fail
 
+[ $compiler == dart2dart && $minified ]
+error_stack_trace1_test: Fail # Fails in minified mode, test depends on method names.
+
 [ $compiler == dartanalyzer ]
 symbol_test/02: Fail
 symbol_test/03: Fail
@@ -115,9 +115,6 @@
 [ $arch == simarm && $mode == debug ]
 collection_to_string_test: Pass, Crash # Issue: 11207
 
-[ $arch == mips ]
-*: Skip
-
 [ $arch == simmips ]
 int_parse_radix_test: Skip # Timeout
 
diff --git a/tests/corelib/error_stack_trace1_test.dart b/tests/corelib/error_stack_trace1_test.dart
new file mode 100644
index 0000000..53df671
--- /dev/null
+++ b/tests/corelib/error_stack_trace1_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+  static Aa() => Ab();
+  static Ab() => Ac();
+  static Ac() => throw "abc";
+}
+
+class B {
+  static Ba() => Bb();
+  static Bb() => Bc();
+  static Bc() {
+    try {
+      A.Aa();
+    } catch (e) {
+      // This should produce a NoSuchMethodError.
+      var trace = e.stackTrace;
+    }
+  }
+}
+
+main() {
+  bool hasThrown = false;
+  try {
+    B.Ba();
+  } catch (e) {
+    hasThrown = true;
+    var trace = e.stackTrace.toString();
+    print(trace);
+    Expect.isTrue(trace.contains("Bc"));
+    Expect.isTrue(trace.contains("Bb"));
+    Expect.isTrue(trace.contains("Ba"));
+    Expect.isTrue(trace.contains("main"));
+  }
+  Expect.isTrue(hasThrown);
+}
diff --git a/tests/html/custom_elements_test.dart b/tests/html/custom_elements_test.dart
index 71714b3..666a0a3 100644
--- a/tests/html/custom_elements_test.dart
+++ b/tests/html/custom_elements_test.dart
@@ -8,12 +8,17 @@
 import 'dart:html';
 
 class CustomType extends Element {
+  factory CustomType() => null;
+
   bool onCreatedCalled = false;
   void onCreated() {
     onCreatedCalled = true;
+    customCreatedCount++;
   }
 }
 
+int customCreatedCount = 0;
+
 class NotAnElement {}
 
 main() {
@@ -95,4 +100,30 @@
       expect(firedOnPost, isTrue);
     });
   });
+
+  group('innerHtml', () {
+    test('query', () {
+      document.register('x-type8', CustomType);
+      var element = new DivElement();
+      element.innerHtml = '<x-type8></x-type8>';
+      document.body.nodes.add(element);
+      var queried = query('x-type8');
+
+      expect(queried, isNotNull);
+      expect(queried is CustomType, isTrue);
+      expect(queried.onCreatedCalled, isTrue);
+    });
+  });
+
+  group('lifecycle', () {
+    test('onCreated', () {
+      int oldCount = customCreatedCount;
+
+      document.register('x-type9', CustomType);
+      var element = new DivElement();
+      element.innerHtml = '<x-type9></x-type9>';
+      document.body.nodes.add(element);
+      expect(customCreatedCount, oldCount + 1);
+    });
+  });
 }
diff --git a/tests/html/html.status b/tests/html/html.status
index 10747a7..a39b862 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -7,8 +7,8 @@
 interactive_test: Skip # Must be run manually.
 
 # Issue 9326
-custom_elements_test/register: Fail
 custom_elements_test/preregister: Fail
+custom_elements_test/lifecycle: Fail
 
 [ $compiler == dart2js ]
 # Document.register is unimplemented.
@@ -96,8 +96,6 @@
 canvasrenderingcontext2d_test/drawImage_video_element: Fail # IE does not support drawImage w/ video element
 canvasrenderingcontext2d_test/drawImage_video_element_dataUrl: Fail # IE does not support drawImage w/ video element
 worker_test/functional: Fail # IE uses incorrect security context for Blob URIs.
-element_test/eventDelegation: Fail # TODO(efortuna)
-element_test/matches: Fail # TODO(efortuna)
 
 # IE10 Feature support statuses-
 # All changes should be accompanied by platform support annotation changes.
@@ -160,7 +158,6 @@
 canvasrenderingcontext2d_test/drawImage_video_element_dataUrl: Fail # IE does not support drawImage w/ video element
 canvasrenderingcontext2d_test/drawImage_image_element: Pass, Fail # Issue: 11416
 input_element_test/attributes: Fail # IE returns null while others ''
-element_test/eventDelegation: Fail # TODO(efortuna)
 
 # IE9 Feature support statuses-
 # All changes should be accompanied by platform support annotation changes.
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 1d3e6f5..73c3a5c 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -22,7 +22,6 @@
 
 [ $compiler == dartanalyzer ]
 isolate2_negative_test: fail
-isolate_import_negative_test: fail
 isolate_negative_test: fail
 spawn_function_negative_test: fail
 spawn_uri_negative_test: fail
@@ -48,10 +47,6 @@
 [ $compiler == dart2js && $runtime == drt ]
 unresolved_ports_negative_test: Pass, Crash # Issue 10613
 
-[ $compiler == dart2js && $runtime == chrome ]
-spawn_uri_negative_test: Pass, Fail, Timeout # Issue: 12239
-spawn_uri_test: Pass, Fail, Timeout # Issue: 12239
-
 [ $compiler == dart2js ]
 serialization_test: Fail # Tries to access class TestingOnly declared in isolate_patch.dart
 illegal_msg_test: Fail # Issue 6750
diff --git a/tests/language/bad_override_test.dart b/tests/language/bad_override_test.dart
index 646df5c..e388914 100644
--- a/tests/language/bad_override_test.dart
+++ b/tests/language/bad_override_test.dart
@@ -21,7 +21,7 @@
   static foo() {}   /// 03: compile-time error
   field() {}        /// 04: compile-time error
   var method;       /// 05: compile-time error
-  nullary(x) {}     /// 06: compile-time error
+  nullary(x) {}     /// 06: static type warning
 }
 
 main() {
diff --git a/tests/language/black_listed_test.dart b/tests/language/black_listed_test.dart
index d5d892e..795e385 100644
--- a/tests/language/black_listed_test.dart
+++ b/tests/language/black_listed_test.dart
@@ -37,7 +37,8 @@
 }                                                       /// 10: continued
 
 // Function.
-class MyFunction implements Function {}                     /// 11: compile-time error
+class MyFunction implements Function {}
+class MyOtherFunction extends Function {}
 abstract class MyFunctionInterface implements Function default F {  /// 12: compile-time error
   MyFunctionInterface();                                    /// 12: continued
 }                                                           /// 12: continued
@@ -71,7 +72,8 @@
   new MyDoubleInterface();   /// 08: continued
   new MyString();            /// 09: continued
   new MyStringInterface();   /// 10: continued
-  new MyFunction();          /// 11: continued
+  new MyFunction();
+  new MyOtherFunction();
   new MyFunctionInterface(); /// 12: continued
   new MyDynamic();           /// 13: continued
   new MyDynamicInterface();  /// 14: continued
diff --git a/tests/language/class_override_negative_test.dart b/tests/language/class_override_negative_test.dart
deleted file mode 100644
index fab3411..0000000
--- a/tests/language/class_override_negative_test.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// 8.1 Methods: It is a compile-time error if a method m1 overrides
-// a method m2 and has a different number of required parameters.
-
-class A {
-  foo() {}
-}
-
-class B extends A {
-  foo(a) { }
-}
-
-main() {
-  B instance = new B();
-  instance.foo(1);
-  print("Success");
-}
diff --git a/tests/language/class_override_test.dart b/tests/language/class_override_test.dart
new file mode 100644
index 0000000..214a08d
--- /dev/null
+++ b/tests/language/class_override_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// It is a static warning if a method m1 overrides a method m2 and has a
+// different number of required parameters.
+
+class A {
+  foo() {}
+}
+
+class B extends A {
+  foo(a) {}  /// 00: static type warning
+}
+
+main() {
+  B instance = new B();
+  try {
+    instance.foo();
+  } on NoSuchMethodEror catch (error) {  /// 00: continued
+  } finally {
+  }
+  print("Success");
+}
diff --git a/tests/language/compile_time_constant_c_test.dart b/tests/language/compile_time_constant_c_test.dart
index b1bd81a..bf3d485 100644
--- a/tests/language/compile_time_constant_c_test.dart
+++ b/tests/language/compile_time_constant_c_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 const m1 = const {
-  499: 400 + 99  /// 01: compile-time error
+  499: 400 + 99
 };
 const m2 = const {
   "foo" + "bar": 42  /// 02: compile-time error
diff --git a/tests/language/dynamic_test.dart b/tests/language/dynamic_test.dart
index 9b1cc77..b871001 100644
--- a/tests/language/dynamic_test.dart
+++ b/tests/language/dynamic_test.dart
@@ -31,6 +31,9 @@
 }
 
 main() {
+  Expect.isTrue(dynamic is Type);
+  Expect.equals(dynamic, dynamic);
+
   M1<dynamic, dynamic> m1 = new M1<dynamic, dynamic>();
   Expect.isTrue(m1 is Iface<dynamic, num>);
   Expect.isTrue(m1 is Iface<String, dynamic>);
diff --git a/tests/language/inferrer_constructor2_test.dart b/tests/language/inferrer_constructor2_test.dart
index 218723b..dbcd2e1 100644
--- a/tests/language/inferrer_constructor2_test.dart
+++ b/tests/language/inferrer_constructor2_test.dart
@@ -13,7 +13,7 @@
   var foo;
   var bar;
 
-  @DontInline
+  @DontInline()
   A() {
     // Currently defeat inlining by using a closure.
     bar = () => 42;
@@ -33,7 +33,7 @@
 class B {
   var bar;
   var closure;
-  @DontInline
+  @DontInline()
   B() {
     // Currently defeat inlining by using a closure.
     closure = () => 42;
@@ -41,7 +41,7 @@
   }
 }
 
-@DontInline
+@DontInline()
 bar() {
   // Make sure B's constructor is analyzed first by surrounding the
   // body by two allocations.
@@ -52,7 +52,7 @@
   new B();
 }
 
-@DontInline
+@DontInline()
 codegenLast() {
   // This assignment currently defeats simple type inference, but not
   // the optimistic inferrer.
diff --git a/tests/language/inferrer_constructor3_test.dart b/tests/language/inferrer_constructor3_test.dart
index b39012b..8afa449 100644
--- a/tests/language/inferrer_constructor3_test.dart
+++ b/tests/language/inferrer_constructor3_test.dart
@@ -24,14 +24,14 @@
   bar();
 }
 
-@DontInline
+@DontInline()
 doIt() {
   () => 42;
   var c = new A(null);
   Expect.throws(() => c.field + 42, (e) => e is NoSuchMethodError);
 }
 
-@DontInline
+@DontInline()
 bar() {
   () => 42;
   return inlineLevel1();
diff --git a/tests/language/issue12023_test.dart b/tests/language/issue12023_test.dart
new file mode 100644
index 0000000..5e1a936b
--- /dev/null
+++ b/tests/language/issue12023_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+void main() {
+  List test = ["f", "5", "s", "6"];
+  int length = test.length;
+  for (int i = 0; i < length;) {
+    var action = test[i++];
+    switch (action) {
+      case "f":
+      case "s":
+        action = test[i - 1];
+        int value = int.parse(test[i++]);
+        if (action == "f") {
+          Expect.equals(5, value);
+        } else {
+          Expect.equals(6, value);
+        }
+        break;
+    }
+  }
+}
diff --git a/tests/language/issue12284_test.dart b/tests/language/issue12284_test.dart
new file mode 100644
index 0000000..efb5883
--- /dev/null
+++ b/tests/language/issue12284_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "compiler_annotations.dart";
+
+class A {
+  int field;
+
+  @DontInline()
+  A(param) {
+    // Currently defeat inlining by using a closure.
+    var bar = () => 42;     
+    field = param + 42;
+  }
+  A.redirect() : this('foo');
+}
+
+main() {
+  Expect.equals(42 + 42, new A(42).field);
+  Expect.throws(() => new A.redirect(),
+                (e) => e is ArgumentError || e is TypeError);
+}
diff --git a/tests/language/issue12288_test.dart b/tests/language/issue12288_test.dart
new file mode 100644
index 0000000..bbe6b92
--- /dev/null
+++ b/tests/language/issue12288_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+  var parent = new Element(null);
+  var child = new Element(parent);
+  var result = child.path0.length;
+  if (result != 2) {
+    throw "Expected 2, but child.path0.length was $result";
+  }
+}
+
+class Element {
+  final Element parent;
+
+  Element(this.parent);
+
+  List<Element> get path0 {
+    if (parent == null) {
+      return <Element>[this];
+    } else {
+      var list = parent.path0;
+      list.add(this);
+      return list;
+    }
+  }
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index cdf20d7..97d31b4 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -30,7 +30,6 @@
 built_in_identifier_prefix_test: Fail # http://dartbug.com/6970
 library_juxtaposition_test: Fail # Issue 6877
 pseudo_kw_illegal_test/14: Fail  # Issue 356
-bound_closure_equality_test: Fail # Issue 10849
 switch_int_double_test/01: Fail # Issue 7307
 switch_int_double_test/02: Fail # Issue 7307
 
@@ -154,8 +153,10 @@
 # Calling unresolved class constructor:
 call_nonexistent_constructor_test: Fail
 
-bad_override_test/01: Fail
-bad_override_test/02: Fail
+bad_override_test/01: Fail # Issue 11496
+bad_override_test/02: Fail # Issue 11496
+bad_override_test/06: Fail # Issue 11496
+class_override_test/00: Fail # Issue 11496
 
 # Missing compile-time error when modifying final local variables
 final_variable_assignment_test/01: Fail
@@ -288,8 +289,6 @@
 
 positional_parameters_type_test: Fail # Triage this.
 
-bound_closure_equality_test: Fail # Issue 10849
-
 [ $compiler == dart2dart && $minified ]
 super_getter_setter_test: Fail # Issue 11065.
 
@@ -300,6 +299,3 @@
 prefix22_test: Pass
 invocation_mirror_test: Fail, OK # hardcoded names.
 super_call4_test: Fail, OK # hardcoded names.
-
-[ $arch == mips ]
-*: Skip
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 194c299..9368478 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -7,27 +7,9 @@
 # Runtime negative test. No static errors or warnings.
 closure_call_wrong_argument_count_negative_test: skip
 
-illegal_invocation_test/01: fail # Issue: 11892
-
-# TBF: m([int p = 'String'])
-assign_static_type_test/06: fail
-
 # TBD: using built-in identifers
 built_in_identifier_prefix_test: fail
 
-# TBF: (o as C) is not rolled back
-cast_test/04: fail
-cast_test/05: fail
-
-# TBF: It is a compile-time error if the superclass of a class C appears in the implements clause of C.
-const_constructor_super_test/01: fail
-compile_time_constant10_test/none: fail
-compile_time_constant_c_test/01: fail
-
-# TBF: m([int p = 'String']) and call 'const' instance creation
-compile_time_constant_checked2_test/03: fail
-compile_time_constant_checked3_test/03: fail
-
 # TBF: It is a static type warning if a type parameter is a supertype of its upper bound.
 cyclic_type_variable_test/01: fail
 cyclic_type_variable_test/02: fail
@@ -51,13 +33,6 @@
 list_literal_syntax_test/03: fail # Issue 12103
 malformed_test/none: fail
 
-# TBF: disallowed in the most recent spec
-named_parameters_aggregated_test/03: fail
-positional_parameters_type_test: fail
-
-# TBF: non-const superinitializer; 7.6.3 Constant Constructors: The superinitializer that appears, explicitly or implicitly, in the initializer list of a constant constructor must specify a constant constructor of the superclass of the immediately enclosing class.
-non_const_super_negative_test: fail
-
 # TBF: 1is int; invalid character in number
 number_identifier_negative_test: fail
 
@@ -77,21 +52,6 @@
 # TBF
 pseudo_kw_test: fail
 
-# TBF: hiding at start of the block and declared after declaration statement
-scope_negative_test: fail
-
-# TBF
-method_override2_test/00: fail # issue 11497
-method_override2_test/01: fail # issue 11497
-method_override2_test/02: fail # issue 11497
-method_override2_test/03: fail # issue 11497
-method_override3_test/00: fail # issue 11497
-method_override3_test/01: fail # issue 11497
-method_override3_test/02: fail # issue 11497
-method_override4_test: fail # issue 11497
-method_override5_test: fail # issue 11497
-method_override6_test: fail # issue 11497
-
 
 
 
@@ -136,11 +96,6 @@
 const_escape_frog_test: fail
 compile_time_constant_test/none: fail
 
-# Test issue 11544, using @TypeName as annotation is not valid
-inferrer_constructor2_test: fail
-inferrer_constructor3_test: fail
-multiple_field_assignment_constructor_test: fail
-
 # Test issue 11545, using not existing constructor name in annotation
 metadata_test: fail
 
@@ -281,7 +236,6 @@
 
 # test issue 12163, unresolved identifier is static warning in static context
 unresolved_in_factory_negative_test: fail
-unresolved_top_level_method_negative_test: fail
 unresolved_top_level_var_negative_test: fail
 
 # test issue 12181, uses argument definition test
@@ -300,6 +254,13 @@
 # test issue 12289, assignment in assert statement
 type_error_test: fail
 
+# test issue 12381, It is compile-time error to invoke not existing function
+issue11724_test: fail
+call_nonexistent_static_test/08: fail
+
+# test issue 12397; it is static warning, not error to use variable before declaration (or hidden)
+scope_negative_test: fail
+
 [ $compiler == dartanalyzer && $checked ]
 factory1_test/00: fail
 factory1_test/01: fail
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 528d5e9..f560c23 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2js || $compiler == dart2dart ]
+compile_time_constant_c_test/none: Fail # Map literal with int key.
 class_literal_test/01: Fail # Class literals are expression now; delete this test.
 class_literal_test/02: Fail # Class literals are expression now; delete this test.
 class_literal_test/05: Fail # Class literals are expression now; delete this test.
@@ -29,6 +30,8 @@
 
 constructor_initializer_test: Fail, OK # Depends on ?parameter check.
 
+black_listed_test/none: Fail # Issue 12446.
+
 # Issues related to undeclared prefix resolution.
 malformed_test/none: Fail
 malformed_test/05: Fail
@@ -110,13 +113,15 @@
 final_variable_assignment_test/02: Fail
 final_variable_assignment_test/03: Fail
 final_variable_assignment_test/04: Fail
-bad_override_test/01: Fail
-bad_override_test/02: Fail
+bad_override_test/01: Fail # Issue 11496
+bad_override_test/02: Fail # Issue 11496
+bad_override_test/06: Fail # Issue 11496
+class_override_test/00: Fail # Issue 11496
 call_nonexistent_constructor_test: Fail
 constructor_named_arguments_test/01: Fail # http://dartbug.com/5519
 getter_no_setter_test/01: Fail # http://dartbug.com/5519
 not_enough_positional_arguments_test/01: Fail # http://dartbug.com/5519
-error_stacktrace_test: Fail # (Issue 11681).
+dynamic_test: Fail # http://dartbug.com/12398
 
 constructor_negative_test: Pass # Wrong reason: the expression 'C()' is valid with class literals.
 
diff --git a/tests/language/multiple_field_assignment_constructor_test.dart b/tests/language/multiple_field_assignment_constructor_test.dart
index 9058c42..88270ac 100644
--- a/tests/language/multiple_field_assignment_constructor_test.dart
+++ b/tests/language/multiple_field_assignment_constructor_test.dart
@@ -11,7 +11,7 @@
   var foo;
   var bar;
 
-  @DontInline
+  @DontInline()
   A() {
     // Currently defeat inlining by using a closure.
     bar = () => 42;
@@ -24,7 +24,7 @@
   var foo;
   var bar;
 
-  @DontInline
+  @DontInline()
   B() {
     // Currently defeat inlining by using a closure.
     bar = () => 42;
@@ -44,7 +44,7 @@
   new B();
 }
 
-@DontInline
+@DontInline()
 bar() {
   // Currently defeat inlining by using a closure.
   Expect.throws(() => new A().foo + 42, (e) => e is NoSuchMethodError);
diff --git a/tests/language/unicode_hash_test.dart b/tests/language/unicode_hash_test.dart
new file mode 100644
index 0000000..3e0946ed
--- /dev/null
+++ b/tests/language/unicode_hash_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+  Expect.equals("\u{10412}", "𐐒");  // Second string is literal U+10412.
+  Expect.equals("\u{10412}".hashCode, "𐐒".hashCode);
+}
diff --git a/tests/lib/convert/codec1_test.dart b/tests/lib/convert/codec1_test.dart
index 6132c96..5b5d9b3 100644
--- a/tests/lib/convert/codec1_test.dart
+++ b/tests/lib/convert/codec1_test.dart
@@ -9,15 +9,19 @@
 class MyCodec extends Codec<int, String> {
   const MyCodec();
 
-  Converter<int, String> get encoder => new IntStringConverter();
-  Converter<String, int> get decoder => new StringIntConverter();
+  final Converter<int, String> encoder = const IntStringConverter();
+  final Converter<String, int> decoder = const StringIntConverter();
 }
 
 class IntStringConverter extends Converter<int, String> {
+  const IntStringConverter();
+
   String convert(int i) => i.toString();
 }
 
 class StringIntConverter extends Converter<String, int> {
+  const StringIntConverter();
+
   int convert(String str) => int.parse(str);
 }
 
diff --git a/tests/lib/convert/line_splitter_test.dart b/tests/lib/convert/line_splitter_test.dart
index acdc633..60a7c29 100644
--- a/tests/lib/convert/line_splitter_test.dart
+++ b/tests/lib/convert/line_splitter_test.dart
@@ -117,64 +117,22 @@
     .transform(new Utf8Decoder())
     .transform(new LineSplitter());
 
-  var done = false;
+  var expectedLines = ['Line1', 'Line2','Line3', 'Line4',
+                       '', '', '', '', '', '',
+                       'Line5', 'Line6'];
 
-  var stage = 0;
-  var subStage = 0;
+  var index = 0;
+
   stream.listen((line) {
-      if (stage == 0) {
-        if (subStage == 0) {
-          Expect.equals("Line1", line);
-          subStage++;
-        } else if (subStage == 1) {
-          Expect.equals("Line2", line);
-          subStage++;
-        } else if (subStage == 2) {
-          Expect.equals("Line3", line);
-          subStage = 0;
-          stage++;
-        } else {
-          Expect.fail("Stage 0 failed");
-        }
-      } else if (stage == 1) {
-        if (subStage == 0) {
-          Expect.equals("Line4", line);
-          subStage = 0;
-          stage++;
-        } else {
-          Expect.fail("Stage 1 failed");
-        }
-      } else if (stage == 2) {
-        if (subStage < 4) {
-          // Expect 5 empty lines. As long as the stream is not closed the
-          // final \r cannot be interpreted as a end of line.
-          Expect.equals("", line);
-          subStage++;
-        } else if (subStage == 4) {
-          Expect.equals("", line);
-          subStage = 0;
-          stage++;
-        } else {
-          Expect.fail("Stage 2 failed");
-        }
-      } else if (stage == 3) {
-        if (subStage == 0) {
-          Expect.equals("", line);
-          stage++;
-        } else {
-          Expect.fail("Stage 3 failed");
-        }
-      }
-    }, onDone: () {
-      Expect.equals(4, stage);
-      Expect.equals(0, subStage);
-      done = true;
-    });
+    Expect.equals(expectedLines[index++], line);
+  });
 
   // Note: codeUnits is fine. Text is ASCII.
   controller.add("Line1\nLine2\r\nLine3\rLi".codeUnits);
   controller.add("ne4\n".codeUnits);
   controller.add("\n\n\r\n\r\n\r\r".codeUnits);
+  controller.add("Line5\r".codeUnits);
+  controller.add("\nLine6\n".codeUnits);
   controller.close();
-  Expect.isTrue(done, 'should be done here...');
+  Expect.equals(expectedLines.length, index);
 }
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 6967e4c..41d369f 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -100,8 +100,8 @@
 
 [ $runtime == vm || ($compiler == none && $runtime == drt) ]
 async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9001.
-mirrors/parameter_test: Fail # http://dartbug.com/11567
 mirrors/operator_test: Fail # http://dartbug.com/11944
+mirrors/mixin_test: Fail # TODO(ahe): This test is slightly broken. http://dartbug.com/12464
 
 [ $compiler == none && $runtime == drt ]
 async/timer_isolate_test: Skip # See Issue 4997
@@ -115,9 +115,6 @@
 async/multiple_timer_test: Fail, Pass # See Issue 10982
 async/timer_test: Fail, Pass # See Issue 10982
 
-[ $arch == mips ]
-*: Skip
-
-[ $arch == simmips ]
+[ $arch == simmips || $arch == mips ]
 convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12025.
 convert/streamed_conversion_json_utf8_decode_test: Pass, Slow
diff --git a/tests/lib/mirrors/generics_test.dart b/tests/lib/mirrors/generics_test.dart
index dcb9093..e5e2c2f 100644
--- a/tests/lib/mirrors/generics_test.dart
+++ b/tests/lib/mirrors/generics_test.dart
@@ -15,6 +15,7 @@
 class E<S> extends A<S> {}
 class F<R> extends A<int> {}
 class G {}
+class H<A,B,C> {}
 
 typeParameters(mirror, parameterNames) {
   Expect.listEquals(parameterNames.map((n) => new Symbol(n)).toList(),
@@ -72,15 +73,25 @@
   typeParameters(reflect(new E()).type, ['S']);
   typeParameters(reflect(new F<num>()).type, ['R']);
   typeParameters(reflect(new G()).type, []);
+  typeParameters(reflect(new H()).type, ['A', 'B', 'C']);
 
   var numMirror = reflectClass(num);
+  var dynamicMirror = currentMirrorSystem().dynamicType;
   typeArguments(reflect(new A<num>()).type, [numMirror]);
+  typeArguments(reflect(new A<dynamic>()).type, [dynamicMirror]);
+  typeArguments(reflect(new A()).type, [dynamicMirror]);
   typeArguments(reflect(new B()).type, []);
   typeArguments(reflect(new C()).type, []);
   typeArguments(reflect(new D()).type, []);
   typeArguments(reflect(new E<num>()).type, [numMirror]);
+  typeArguments(reflect(new E<dynamic>()).type, [dynamicMirror]);
+  typeArguments(reflect(new E()).type, [dynamicMirror]);
   typeArguments(reflect(new F<num>()).type, [numMirror]);
+  typeArguments(reflect(new F<dynamic>()).type, [dynamicMirror]);
+  typeArguments(reflect(new F()).type, [dynamicMirror]);
   typeArguments(reflect(new G()).type, []);
+  typeArguments(reflect(new H<dynamic, num, dynamic>()).type,
+      [dynamicMirror, numMirror, dynamicMirror]);
 
   Expect.isFalse(reflect(new A<num>()).type.isOriginalDeclaration);
   Expect.isTrue(reflect(new B()).type.isOriginalDeclaration);
@@ -89,6 +100,7 @@
   Expect.isFalse(reflect(new E<num>()).type.isOriginalDeclaration);
   Expect.isFalse(reflect(new F<num>()).type.isOriginalDeclaration);
   Expect.isTrue(reflect(new G()).type.isOriginalDeclaration);
+  Expect.isFalse(reflect(new H()).type.isOriginalDeclaration);
 
   Expect.equals(reflectClass(A),
                 reflect(new A<num>()).type.originalDeclaration);
@@ -104,6 +116,8 @@
                 reflect(new F<num>()).type.originalDeclaration);
   Expect.equals(reflectClass(G),
                 reflect(new G()).type.originalDeclaration);
+  Expect.equals(reflectClass(H),
+                reflect(new H()).type.originalDeclaration);
 
   Expect.notEquals(reflect(new A<num>()).type,
                    reflect(new A<num>()).type.originalDeclaration);
@@ -119,6 +133,8 @@
                    reflect(new F<num>()).type.originalDeclaration);
   Expect.equals(reflect(new G()).type,
                 reflect(new G()).type.originalDeclaration);
+  Expect.notEquals(reflect(new H()).type,
+                   reflect(new H()).type.originalDeclaration);
 
   // Library members are all uninstantaited generics or non-generics.
   currentMirrorSystem().libraries.values.forEach((libraryMirror) {
diff --git a/tests/lib/mirrors/intercepted_cache_test.dart b/tests/lib/mirrors/intercepted_cache_test.dart
new file mode 100644
index 0000000..58dff6d
--- /dev/null
+++ b/tests/lib/mirrors/intercepted_cache_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This is a test for a problem in how dart2js cached InstanceMirror.invoke,
+// etc. The test is using getField, as invoke, setField, and getField all share
+// the same caching.
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+
+class Foo {
+  Foo(this.length);
+  int length;
+}
+
+main() {
+  Expect.equals(
+      1, reflect(new Foo(1)).getField(const Symbol('length')).reflectee);
+  Expect.equals(
+      2, reflect(new Foo(2)).getField(const Symbol('length')).reflectee);
+  Expect.equals(0, reflect([]).getField(const Symbol('length')).reflectee);
+}
diff --git a/tests/lib/mirrors/mixin_test.dart b/tests/lib/mirrors/mixin_test.dart
new file mode 100644
index 0000000..86ca0c8
--- /dev/null
+++ b/tests/lib/mirrors/mixin_test.dart
@@ -0,0 +1,267 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(ahe): This test is sligthly broken but provides temporary test coverage
+// for dart2js. See http://dartbug.com/12464.
+
+library test.mixin_test;
+
+@MirrorsUsed(targets: 'test.mixin_test, test.model, Object', override: '*')
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+import 'model.dart';
+import 'stringify.dart';
+
+class Mixin {
+  int i;
+  m() {}
+}
+
+class Mixin2 {
+  int i2;
+  m2() {}
+}
+
+typedef MixinApplication = C with Mixin;
+typedef MixinApplicationA = C with Mixin, Mixin2;
+
+typedef UnusedMixinApplication = C with Mixin;
+
+class Subclass extends C with Mixin {
+  f() {}
+}
+
+class Subclass2 extends MixinApplication {
+  g() {}
+}
+
+class SubclassA extends C with Mixin, Mixin2 {
+  fa() {}
+}
+
+class Subclass2A extends MixinApplicationA {
+  ga() {}
+}
+
+checkClass(Type type, List<String> expectedSuperclasses) {
+  int i = 0;
+  for (var cls = reflectClass(type); cls != null; cls = cls.superclass) {
+    expect(expectedSuperclasses[i++], cls);
+  }
+  Expect.equals(i, expectedSuperclasses.length, '$type');
+}
+
+expectSame(ClassMirror a, ClassMirror b) {
+  Expect.equals(a, b);
+  expect(stringify(a), b);
+  expect(stringify(b), a);
+}
+
+testMixin() {
+  checkClass(Mixin, [
+      'Class(s(Mixin) in s(test.mixin_test), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+  expect(
+      '{Mixin: Method(s(Mixin) in s(Mixin), constructor),'
+      ' i: Variable(s(i) in s(Mixin)),'
+      ' m: Method(s(m) in s(Mixin))}',
+      reflectClass(Mixin).members);
+}
+
+testMixin2() {
+  checkClass(Mixin2, [
+      'Class(s(Mixin2) in s(test.mixin_test), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+  expect(
+      '{Mixin2: Method(s(Mixin2) in s(Mixin2), constructor),'
+      ' i2: Variable(s(i2) in s(Mixin2)),'
+      ' m2: Method(s(m2) in s(Mixin2))}',
+      reflectClass(Mixin2).members);
+}
+
+testMixinApplication() {
+  checkClass(MixinApplication, [
+      'Class(s(MixinApplication) in s(test.mixin_test), top-level)',
+      'Class(s(C) in s(test.model), top-level)',
+      'Class(s(B) in s(test.model), top-level)',
+      'Class(s(A) in s(test.model), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+
+  expect(
+      '{MixinApplication: Method(s(MixinApplication) in s(MixinApplication),'
+      ' constructor),'
+      ' i: Variable(s(i) in s(MixinApplication)),'
+      ' m: Method(s(m) in s(MixinApplication))}',
+      reflectClass(MixinApplication).members);
+
+  expectSame(reflectClass(C), reflectClass(MixinApplication).superclass);
+}
+
+testMixinApplicationA() {
+  checkClass(MixinApplicationA, [
+      'Class(s(MixinApplicationA) in s(test.mixin_test), top-level)',
+      'Class(s(test.mixin_test.Mixin(test.model.C)), top-level)',
+      'Class(s(C) in s(test.model), top-level)',
+      'Class(s(B) in s(test.model), top-level)',
+      'Class(s(A) in s(test.model), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+
+  expect(
+      '{MixinApplicationA: Method(s(MixinApplicationA) in s(MixinApplicationA),'
+      ' constructor),'
+      ' i2: Variable(s(i2) in s(MixinApplicationA)),'
+      ' m2: Method(s(m2) in s(MixinApplicationA))}',
+      reflectClass(MixinApplicationA).members);
+
+  expect(
+       // TODO(ahe): The owner should probably be the mixin application.
+      '{Mixin: Method(s(Mixin) in s(Mixin), constructor),'
+      ' i: Variable(s(i) in s(Mixin)),'
+      ' m: Method(s(m) in s(Mixin))}',
+      reflectClass(MixinApplicationA).superclass.members);
+
+  expectSame(
+      reflectClass(C),
+      reflectClass(MixinApplicationA).superclass.superclass);
+}
+
+testUnusedMixinApplication() {
+  checkClass(UnusedMixinApplication, [
+      'Class(s(UnusedMixinApplication) in s(test.mixin_test), top-level)',
+      'Class(s(C) in s(test.model), top-level)',
+      'Class(s(B) in s(test.model), top-level)',
+      'Class(s(A) in s(test.model), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+
+  expect(
+      '{UnusedMixinApplication: Method(s(UnusedMixinApplication)'
+      ' in s(UnusedMixinApplication), constructor),'
+      ' i: Variable(s(i) in s(UnusedMixinApplication)),'
+      ' m: Method(s(m) in s(UnusedMixinApplication))}',
+      reflectClass(UnusedMixinApplication).members);
+
+  expectSame(reflectClass(C), reflectClass(UnusedMixinApplication).superclass);
+}
+
+testSubclass() {
+  checkClass(Subclass, [
+      'Class(s(Subclass) in s(test.mixin_test), top-level)',
+      'Class(s(test.mixin_test.Mixin(test.model.C)), top-level)',
+      'Class(s(C) in s(test.model), top-level)',
+      'Class(s(B) in s(test.model), top-level)',
+      'Class(s(A) in s(test.model), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+
+  expect(
+      '{Subclass: Method(s(Subclass) in s(Subclass), constructor),'
+      ' f: Method(s(f) in s(Subclass))}',
+      reflectClass(Subclass).members);
+
+  expect(
+       // TODO(ahe): The owner should probably be the mixin application.
+      '{Mixin: Method(s(Mixin) in s(Mixin), constructor),'
+      ' i: Variable(s(i) in s(Mixin)),'
+      ' m: Method(s(m) in s(Mixin))}',
+      reflectClass(Subclass).superclass.members);
+
+  expectSame(
+      reflectClass(C),
+      reflectClass(Subclass).superclass.superclass);
+}
+
+testSubclass2() {
+  checkClass(Subclass2, [
+      'Class(s(Subclass2) in s(test.mixin_test), top-level)',
+      'Class(s(MixinApplication) in s(test.mixin_test), top-level)',
+      'Class(s(C) in s(test.model), top-level)',
+      'Class(s(B) in s(test.model), top-level)',
+      'Class(s(A) in s(test.model), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+
+  expect(
+      '{Subclass2: Method(s(Subclass2) in s(Subclass2), constructor),'
+      ' g: Method(s(g) in s(Subclass2))}',
+      reflectClass(Subclass2).members);
+
+  expectSame(
+      reflectClass(MixinApplication),
+      reflectClass(Subclass2).superclass);
+}
+
+testSubclassA() {
+  checkClass(SubclassA, [
+      'Class(s(SubclassA) in s(test.mixin_test), top-level)',
+      'Class(s(test.mixin_test.Mixin2(test.mixin_test.Mixin(test.model.C))),'
+      ' top-level)',
+      'Class(s(test.mixin_test.Mixin(test.model.C)), top-level)',
+      'Class(s(C) in s(test.model), top-level)',
+      'Class(s(B) in s(test.model), top-level)',
+      'Class(s(A) in s(test.model), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+
+  expect(
+      '{SubclassA: Method(s(SubclassA) in s(SubclassA), constructor),'
+      ' fa: Method(s(fa) in s(SubclassA))}',
+      reflectClass(SubclassA).members);
+
+  expect(
+       // TODO(ahe): The owner should probably be the mixin application.
+      '{Mixin2: Method(s(Mixin2) in s(Mixin2), constructor),'
+      ' i2: Variable(s(i2) in s(Mixin2)),'
+      ' m2: Method(s(m2) in s(Mixin2))}',
+      reflectClass(SubclassA).superclass.members);
+
+  expect(
+       // TODO(ahe): The owner should probably be the mixin application.
+      '{Mixin: Method(s(Mixin) in s(Mixin), constructor),'
+      ' i: Variable(s(i) in s(Mixin)),'
+      ' m: Method(s(m) in s(Mixin))}',
+      reflectClass(SubclassA).superclass.superclass.members);
+
+  expectSame(
+      reflectClass(C),
+      reflectClass(SubclassA).superclass.superclass.superclass);
+}
+
+testSubclass2A() {
+  checkClass(Subclass2A, [
+      'Class(s(Subclass2A) in s(test.mixin_test), top-level)',
+      'Class(s(MixinApplicationA) in s(test.mixin_test), top-level)',
+      'Class(s(test.mixin_test.Mixin(test.model.C)), top-level)',
+      'Class(s(C) in s(test.model), top-level)',
+      'Class(s(B) in s(test.model), top-level)',
+      'Class(s(A) in s(test.model), top-level)',
+      'Class(s(Object) in s(dart.core), top-level)',
+  ]);
+
+  expect(
+      '{Subclass2A: Method(s(Subclass2A) in s(Subclass2A), constructor),'
+      ' ga: Method(s(ga) in s(Subclass2A))}',
+      reflectClass(Subclass2A).members);
+
+  expectSame(reflectClass(MixinApplicationA),
+             reflectClass(Subclass2A).superclass);
+}
+
+main() {
+  testMixin();
+  testMixin2();
+  testMixinApplication();
+  testMixinApplicationA();
+  testUnusedMixinApplication();
+  testSubclass();
+  testSubclass2();
+  testSubclassA();
+  testSubclass2A();
+}
diff --git a/tests/lib/mirrors/stringify.dart b/tests/lib/mirrors/stringify.dart
index 0e3b2c0..731403b 100644
--- a/tests/lib/mirrors/stringify.dart
+++ b/tests/lib/mirrors/stringify.dart
@@ -66,9 +66,11 @@
   writeVariableOn(parameter, buffer);
   if (parameter.isOptional) buffer.write(', optional');
   if (parameter.isNamed) buffer.write(', named');
-  if (parameter.hasDefaultValue) {
-    buffer.write(', value = ${stringify(parameter.defaultValue)}');
-  }
+  // TODO(6490,12430): Add this check as soon as it's properly implemented in
+  // the VM and dart2js.
+  // if (parameter.hasDefaultValue) {
+  //  buffer.write(', value = ${stringify(parameter.defaultValue)}');
+  // }
   // TODO(ahe): Move to writeVariableOn.
   buffer.write(', type = ${stringify(parameter.type)}');
   return 'Parameter($buffer)';
diff --git a/tests/standalone/io/certificate_test.dart b/tests/standalone/io/certificate_test.dart
index fb5b423..b4c8796 100644
--- a/tests/standalone/io/certificate_test.dart
+++ b/tests/standalone/io/certificate_test.dart
@@ -21,9 +21,9 @@
                         server.port.toString(),
                         join(scriptDir, 'pkcert', 'myauthority.pem')]);
   }).then((ProcessResult result) {
-    if (result.exitCode != 0) {
+    if (result.exitCode != 0 || !result.stdout.contains("SUCCESS")) {
       print("Client failed with exit code ${result.exitCode}");
-      print("  stdout:");
+      print("  stdout (expects \"SUCCESS\\n\"):");
       print(result.stdout);
       print("  stderr:");
       print(result.stderr);
diff --git a/tests/standalone/io/certificate_test_client.dart b/tests/standalone/io/certificate_test_client.dart
index f7f2fb2..4e3262d 100644
--- a/tests/standalone/io/certificate_test_client.dart
+++ b/tests/standalone/io/certificate_test_client.dart
@@ -21,7 +21,7 @@
   } on CertificateException catch (e) {
     threw = true;
   }
-  if (!threw) throw new AssertException("Expected bad certificate to throw");
+  if (!threw) throw "Expected bad certificate to throw";
 
   threw = false;
   try {
@@ -29,13 +29,37 @@
   } on CertificateException catch (e) {
     threw = true;
   }
-  if (!threw) throw new AssertException("Expected bad trust string to throw");
+  if (!threw) throw "Expected bad trust string to throw";
 
   SecureSocket.addCertificate(mycert,
                               SecureSocket.TRUST_ISSUE_SERVER_CERTIFICATES);
+
   SecureSocket.connect('localhost', port).then((SecureSocket socket) {
-    socket.writeln("hello world");
+    socket.writeln('hello world');
     socket.listen((data) { });
-    socket.close();
+    return socket.close();
+  }).then((_) {
+    SecureSocket.changeTrust('myauthority_cert', ',,');
+    return SecureSocket.connect('localhost', port);
+  }).then((_) {
+    throw "Expected untrusted authority to stop connection";
+  }, onError: (e) {
+    if (e is! CertificateException) throw e;
+  }).then((_) {
+    SecureSocket.changeTrust('myauthority_cert', 'C,,');
+    return SecureSocket.connect('localhost', port);
+  }).then((SecureSocket socket) {
+    socket.writeln('hello world');
+    socket.listen((data) { });
+    return socket.close();
+  }).then((_) {
+    SecureSocket.removeCertificate('myauthority_cert');
+    return SecureSocket.connect('localhost', port);
+  }).then((_) {
+    throw "Expected untrusted root to stop connection";
+  }, onError: (e) {
+    if (e is! CertificateException) throw e;
+  }).then((_) {
+    print('SUCCESS');  // Checked by parent process.
   });
 }
diff --git a/tests/standalone/io/certificate_test_client_database.dart b/tests/standalone/io/certificate_test_client_database.dart
new file mode 100644
index 0000000..9723a6a
--- /dev/null
+++ b/tests/standalone/io/certificate_test_client_database.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Client that tests that a certificate authority certificate loaded
+// at runtime can be used to verify a certificate chain. The server it
+// connects to uses localhost_cert, signed by myauthority_cert, to connect
+// securely.  This client tests that addCertificate works if a certificate
+// database has been specified.
+
+import 'dart:io';
+
+void main() {
+  int port = int.parse(new Options().arguments[0]);
+  String certificate = new Options().arguments[1];
+  String database = new Options().arguments[2];
+  SecureSocket.initialize(database: database,
+                          password: 'dartdart',
+                          readOnly: false);
+  SecureSocket.removeCertificate('localhost_cert');
+  SecureSocket.removeCertificate('myauthority_cert');
+  var mycert = new File(certificate).readAsBytesSync();
+  SecureSocket.addCertificate(mycert,
+                              SecureSocket.TRUST_ISSUE_SERVER_CERTIFICATES);
+  if (null != SecureSocket.getCertificate('myauthority_cert')) {
+    throw "Expected getCertificate to return null";
+  }
+  SecureSocket.connect('localhost', port).then((SecureSocket socket) {
+    socket.writeln('hello world');
+    socket.listen((data) { });
+    return socket.close();
+  }).then((_) {
+    // The certificate is only in the in-memory cache, so cannot be removed.
+    try {
+      SecureSocket.removeCertificate('myauthority_cert');
+    } catch (e) {
+      if (e is! CertificateException) throw "error $e";
+    }
+  }).then((_) {
+    print('SUCCESS');  // Checked by parent process.
+  });
+}
diff --git a/tests/standalone/io/delete_a_directory_later.dart b/tests/standalone/io/delete_a_directory_later.dart
new file mode 100644
index 0000000..5e6da0d
--- /dev/null
+++ b/tests/standalone/io/delete_a_directory_later.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:io";
+import "dart:async";
+
+main() {
+  new Timer(new Duration(seconds: 2), () {
+    new Directory(new Options().arguments[0]).delete(recursive: true);
+  });
+}
diff --git a/tests/standalone/io/https_bad_certificate_client.dart b/tests/standalone/io/https_bad_certificate_client.dart
new file mode 100644
index 0000000..4fe59a9
--- /dev/null
+++ b/tests/standalone/io/https_bad_certificate_client.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Client for https_bad_certificate_test, that runs in a subprocess.
+// It verifies that the client bad certificate callback works in HttpClient.
+
+import "dart:async";
+import "dart:io";
+
+class ExpectException implements Exception {
+  ExpectException(this.message);
+  String toString() => "ExpectException: $message";
+  String message;
+}
+
+void expect(condition) {
+  if (!condition) {
+    throw new ExpectException('');
+  }
+}
+
+const HOST_NAME = "localhost";
+
+Future runHttpClient(int port, result) {
+  bool badCertificateCallback(X509Certificate certificate,
+                              String host,
+                              int callbackPort) {
+    expect(HOST_NAME == host);
+    expect(callbackPort == port);
+    expect('CN=localhost' == certificate.subject);
+    expect('CN=myauthority' == certificate.issuer);
+    expect(result != 'exception');  // Throw exception if one is requested.
+    if (result == 'true') return true;
+    if (result == 'false') return false;
+    return result;
+  }
+
+  HttpClient client = new HttpClient();
+
+  var testFutures = [];
+  testFutures.add(client.getUrl(Uri.parse('https://$HOST_NAME:$port/$result'))
+    .then((HttpClientRequest request) {
+      expect(false);
+    }, onError: (e) {
+      expect(e is HandshakeException || e is SocketException);
+    }));
+
+  client.badCertificateCallback = badCertificateCallback;
+  testFutures.add(client.getUrl(Uri.parse('https://$HOST_NAME:$port/$result'))
+    .then((HttpClientRequest request) {
+      expect(result == 'true');
+      request.close().then((result) { });
+    }, onError: (e) {
+      if (result == 'false') expect (e is HandshakeException ||
+                                     e is SocketException);
+      else if (result == 'exception') expect (e is ExpectException ||
+                                              e is SocketException);
+      else expect (e is ArgumentError || e is SocketException);
+    }));
+
+  client.badCertificateCallback = null;
+  testFutures.add(client.getUrl(Uri.parse('https://$HOST_NAME:$port/$result'))
+    .then((HttpClientRequest request) {
+      expect(false);
+    }, onError: (e) {
+      expect(e is HandshakeException || e is SocketException);
+    }));
+
+  return Future.wait(testFutures);
+}
+
+void main() {
+  final args = new Options().arguments;
+  SecureSocket.initialize();
+  int port = int.parse(args[0]);
+  runHttpClient(port, args[1])
+    .then((_) => print('SUCCESS'));
+}
diff --git a/tests/standalone/io/https_bad_certificate_test.dart b/tests/standalone/io/https_bad_certificate_test.dart
new file mode 100644
index 0000000..9023680
--- /dev/null
+++ b/tests/standalone/io/https_bad_certificate_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that the bad certificate callback works in HttpClient.
+
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+import "dart:async";
+import "dart:io";
+
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+
+Future<SecureServerSocket> runServer() {
+  SecureSocket.initialize(
+      database: join(dirname(new Options().script), 'pkcert'),
+      password: 'dartdart');
+
+  return HttpServer.bindSecure(
+      HOST_NAME, 0, backlog: 5, certificateName: 'localhost_cert')
+  .then((server) {
+    server.listen((HttpRequest request) {
+      request.listen((_) { }, onDone: () { request.response.close(); });
+    }, onError: (e) { if (e is! HandshakeException) throw e; });
+    return server;
+  });
+}
+
+void main() {
+  final options = new Options();
+  var clientScript =
+      join(dirname(options.script), 'https_bad_certificate_client.dart');
+
+  Future clientProcess(int port, String acceptCertificate) {
+    return Process.run(options.executable,
+        [clientScript, port.toString(), acceptCertificate])
+    .then((ProcessResult result) {
+      if (result.exitCode != 0 || !result.stdout.contains('SUCCESS')) {
+        print("Client failed, acceptCertificate: $acceptCertificate");
+        print("  stdout:");
+        print(result.stdout);
+        print("  stderr:");
+        print(result.stderr);
+        Expect.fail('Client subprocess exit code: ${result.exitCode}');
+      }
+    });
+  }
+
+  runServer().then((server) {
+    Future.wait([clientProcess(server.port, 'true'),
+                 clientProcess(server.port, 'false'),
+                 clientProcess(server.port, 'fisk'),
+                 clientProcess(server.port, 'exception')]).then((_) {
+      server.close();
+    });
+  });
+}
diff --git a/tests/standalone/io/https_unauthorized_client.dart b/tests/standalone/io/https_unauthorized_client.dart
new file mode 100644
index 0000000..e2057a1
--- /dev/null
+++ b/tests/standalone/io/https_unauthorized_client.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Client that makes HttpClient secure gets from a server that replies with
+// a certificate that can't be authenticated.  This checks that all the
+// futures returned from these connection attempts complete (with errors).
+
+import "dart:async";
+import "dart:io";
+
+class ExpectException implements Exception {
+  ExpectException(this.message);
+  String toString() => "ExpectException: $message";
+  String message;
+}
+
+void expect(condition) {
+  if (!condition) {
+    throw new ExpectException('');
+  }
+}
+
+const HOST_NAME = "localhost";
+
+Future runClients(int port) {
+  HttpClient client = new HttpClient();
+
+  var testFutures = [];
+  for (int i = 0; i < 20; ++i) {
+    testFutures.add(
+        client.getUrl(Uri.parse('https://$HOST_NAME:$port/'))
+          .then((HttpClientRequest request) {
+            expect(false);
+          }, onError: (e) {
+            expect(e is HandshakeException || e is SocketException);
+          }));
+  }
+  return Future.wait(testFutures);
+}
+
+void main() {
+  final args = new Options().arguments;
+  SecureSocket.initialize();
+  runClients(int.parse(args[0]))
+    .then((_) => print('SUCCESS'));
+}
diff --git a/tests/standalone/io/https_unauthorized_test.dart b/tests/standalone/io/https_unauthorized_test.dart
new file mode 100644
index 0000000..f8fe731
--- /dev/null
+++ b/tests/standalone/io/https_unauthorized_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that secure connections that fail due to
+// unauthenticated certificates throw exceptions in HttpClient.
+
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+import "dart:async";
+import "dart:io";
+
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+
+Future<SecureServerSocket> runServer() {
+  SecureSocket.initialize(
+      database: join(dirname(new Options().script), 'pkcert'),
+      password: 'dartdart');
+
+  return HttpServer.bindSecure(
+      HOST_NAME, 0, backlog: 5, certificateName: 'localhost_cert')
+  .then((server) {
+    server.listen((HttpRequest request) {
+      request.listen((_) { }, onDone: () { request.response.close(); });
+    }, onError: (e) { if (e is! HandshakeException) throw e; });
+    return server;
+  });
+}
+
+void main() {
+  final options = new Options();
+  var clientScript = join(dirname(options.script),
+                          'https_unauthorized_client.dart');
+
+  Future clientProcess(int port) {
+    return Process.run(options.executable,
+        [clientScript, port.toString()])
+    .then((ProcessResult result) {
+      if (result.exitCode != 0 || !result.stdout.contains('SUCCESS')) {
+        print("Client failed");
+        print("  stdout:");
+        print(result.stdout);
+        print("  stderr:");
+        print(result.stderr);
+        Expect.fail('Client subprocess exit code: ${result.exitCode}');
+      }
+    });
+  }
+
+  runServer().then((server) {
+    clientProcess(server.port).then((_) {
+      server.close();
+    });
+  });
+}
diff --git a/tests/standalone/io/link_async_test.dart b/tests/standalone/io/link_async_test.dart
index 5826b3e..d910749 100644
--- a/tests/standalone/io/link_async_test.dart
+++ b/tests/standalone/io/link_async_test.dart
@@ -181,6 +181,24 @@
     .then((_) => Expect.isFalse(link2.existsSync()));
   }
 
+  Future testUpdate(String base , String target1, String target2) {
+    Link link1;
+    return new Link(join(base, 'c')).create(target1)
+    .then((link) {
+      link1 = link;
+      Expect.isTrue(link1.existsSync());
+      return link1.update(target2);
+    })
+    .then((Link link) {
+      Expect.isTrue(link1.existsSync());
+      Expect.isTrue(link.existsSync());
+      return FutureExpect.equals(target2, link.target())
+      .then((_) => FutureExpect.equals(target2, link1.target()))
+      .then((_) => link.delete());
+    })
+    .then((_) => Expect.isFalse(link1.existsSync()));
+  }
+
   return new Directory('').createTemp().then((baseDir) {
     String base = baseDir.path;
     var targetsFutures = [];
@@ -195,6 +213,7 @@
     return Future.wait(targetsFutures).then((targets) {
       return testRename(base, targets[0].path)
       .then((_) => testRename(base, targets[1].path))
+      .then((_) => testUpdate(base, targets[0].path, targets[1].path))
       .then((_) => baseDir.delete(recursive: true));
     });
   });
diff --git a/tests/standalone/io/pkcert/localhost.p12 b/tests/standalone/io/pkcert/localhost.p12
new file mode 100644
index 0000000..97bb4eb
--- /dev/null
+++ b/tests/standalone/io/pkcert/localhost.p12
Binary files differ
diff --git a/tests/standalone/io/process_sync_script.dart b/tests/standalone/io/process_sync_script.dart
new file mode 100644
index 0000000..d8aab9c
--- /dev/null
+++ b/tests/standalone/io/process_sync_script.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Utility script to generate some output on stdout and stderr.
+
+import "dart:math";
+import "dart:io";
+
+main() {
+  var options = new Options();
+  var blockCount = int.parse(options.arguments[0]);
+  var stdoutBlockSize = int.parse(options.arguments[1]);
+  var stderrBlockSize = int.parse(options.arguments[2]);
+  var stdoutBlock =
+      new String.fromCharCodes(new List.filled(stdoutBlockSize, 65));
+  var stderrBlock =
+      new String.fromCharCodes(new List.filled(stderrBlockSize, 66));
+  for (int i = 0; i < blockCount; i++) {
+    stdout.write(stdoutBlock);
+    stderr.write(stderrBlock);
+  }
+  exit(int.parse(options.arguments[3]));
+}
diff --git a/tests/standalone/io/process_sync_test.dart b/tests/standalone/io/process_sync_test.dart
new file mode 100644
index 0000000..04bc59f
--- /dev/null
+++ b/tests/standalone/io/process_sync_test.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'package:path/path.dart';
+import "dart:io";
+
+test(int blockCount,
+     int stdoutBlockSize,
+     int stderrBlockSize,
+     int exitCode,
+     [int nonWindowsExitCode]) {
+  // Get the Dart script file that generates output.
+  var scriptFile = new File(join(dirname(Platform.script),
+                                 "process_sync_script.dart"));
+  var args = [scriptFile.path,
+              blockCount.toString(),
+              stdoutBlockSize.toString(),
+              stderrBlockSize.toString(),
+              exitCode.toString()];
+  ProcessResult syncResult = Process.runSync(Platform.executable, args);
+  Expect.equals(blockCount * stdoutBlockSize, syncResult.stdout.length);
+  Expect.equals(blockCount * stderrBlockSize, syncResult.stderr.length);
+  if (Platform.isWindows) {
+    Expect.equals(exitCode, syncResult.exitCode);
+  } else {
+    if (nonWindowsExitCode == null) {
+      Expect.equals(exitCode, syncResult.exitCode);
+    } else {
+      Expect.equals(nonWindowsExitCode, syncResult.exitCode);
+    }
+  }
+  Process.run(Platform.executable, args).then((asyncResult) {
+    Expect.equals(syncResult.stdout, asyncResult.stdout);
+    Expect.equals(syncResult.stderr, asyncResult.stderr);
+    Expect.equals(syncResult.exitCode, asyncResult.exitCode);
+  });
+}
+
+main() {
+  test(10, 10, 10, 0);
+  test(10, 100, 10, 0);
+  test(10, 10, 100, 0);
+  test(100, 1, 10, 0);
+  test(100, 10, 1, 0);
+  test(100, 1, 1, 0);
+  test(1, 100000, 100000, 0);
+
+  // The buffer size used in process.h.
+  var kBufferSize = 16 * 1024;
+  test(1, kBufferSize, kBufferSize, 0);
+  test(1, kBufferSize - 1, kBufferSize + 1, 0);
+  test(kBufferSize - 1, 1, 1, 0);
+  test(kBufferSize, 1, 1, 0);
+  test(kBufferSize + 1, 1, 1, 0);
+
+  test(10, 10, 10, 1);
+  test(10, 10, 10, 255);
+  test(10, 10, 10, -1, 255);
+  test(10, 10, 10, -255, 1);
+}
+
diff --git a/tests/standalone/io/secure_unauthorized_client.dart b/tests/standalone/io/secure_unauthorized_client.dart
new file mode 100644
index 0000000..964c63c
--- /dev/null
+++ b/tests/standalone/io/secure_unauthorized_client.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Client for secure_bad_certificate_test, that runs in a subprocess.
+// The test verifies that the client bad certificate callback works.
+
+import "dart:async";
+import "dart:io";
+
+class ExpectException implements Exception {
+  ExpectException(this.message);
+  String toString() => "ExpectException: $message";
+  String message;
+}
+
+void expect(condition) {
+  if (!condition) {
+    throw new ExpectException('');
+  }
+}
+
+const HOST_NAME = "localhost";
+
+Future runClients(int port) {
+  var testFutures = [];
+  for (int i = 0; i < 20; ++i) {
+    testFutures.add(
+        SecureSocket.connect(HOST_NAME, port)
+          .then((SecureSocket socket) {
+            expect(false);
+          }, onError: (e) {
+            expect(e is HandshakeException || e is SocketException);
+          }));
+  }
+  return Future.wait(testFutures);
+}
+
+
+void main() {
+  final args = new Options().arguments;
+  SecureSocket.initialize();
+  runClients(int.parse(args[0]))
+    .then((_) => print('SUCCESS'));
+}
diff --git a/tests/standalone/io/secure_unauthorized_test.dart b/tests/standalone/io/secure_unauthorized_test.dart
new file mode 100644
index 0000000..a86b95c
--- /dev/null
+++ b/tests/standalone/io/secure_unauthorized_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that failing secure connection attempts always complete
+// their returned future.
+
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+import "dart:async";
+import "dart:io";
+
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+
+Future<SecureServerSocket> runServer() {
+  SecureSocket.initialize(
+      database: join(dirname(new Options().script), 'pkcert'),
+      password: 'dartdart');
+
+  return SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE)
+      .then((SecureServerSocket server) {
+    server.listen((SecureSocket socket) {
+      socket.listen((_) { },
+                    onDone: () {
+                      socket.close();
+                    });
+    }, onError: (e) => Expect.isTrue(e is HandshakeException));
+    return server;
+  });
+}
+
+void main() {
+  final options = new Options();
+  var clientScript = join(dirname(options.script),
+                          'secure_unauthorized_client.dart');
+
+  Future clientProcess(int port) {
+    return Process.run(options.executable,
+        [clientScript, port.toString()])
+    .then((ProcessResult result) {
+      if (result.exitCode != 0 || !result.stdout.contains('SUCCESS')) {
+        print("Client failed");
+        print("  stdout:");
+        print(result.stdout);
+        print("  stderr:");
+        print(result.stderr);
+        Expect.fail('Client subprocess exit code: ${result.exitCode}');
+      }
+    });
+  }
+
+  runServer().then((server) {
+    clientProcess(server.port).then((_) {
+      server.close();
+    });
+  });
+}
diff --git a/tests/standalone/io/string_transformer_test.dart b/tests/standalone/io/string_transformer_test.dart
index e9e11b5..054f973 100644
--- a/tests/standalone/io/string_transformer_test.dart
+++ b/tests/standalone/io/string_transformer_test.dart
@@ -8,6 +8,16 @@
 import "dart:isolate";
 import "dart:utf";
 
+void main() {
+  testUtf8();
+  testLatin1();
+  testAscii();
+  testReadLine1();
+  testReadLine2();
+  testErrorHandler();
+  testLatin1EncoderError();
+}
+
 void testUtf8() {
   List<int> data = [0x01,
                     0x7f,
@@ -96,26 +106,23 @@
   var stage = 0;
 
   void stringData(line) {
-    var line;
-    if (stage == 0) {
-      Expect.equals(null, line);
-      stage++;
-      controller.close();
-    } else if (stage == 1) {
-      Expect.equals("Line", line);
-      stage++;
-    }
+    Expect.equals(stage, 0);
+    Expect.equals("Line", line);
+    stage++;
   }
 
   void streamClosed() {
-    Expect.equals(2, stage);
+    Expect.equals(1, stage);
   }
 
   stream.listen(
       stringData,
       onDone: streamClosed);
 
+  // Note: codeUnits is fine. Text is ASCII.
   controller.add("Line".codeUnits);
+  controller.close();
+  Expect.equals(1, stage);
 }
 
 void testReadLine2() {
@@ -125,68 +132,31 @@
     .transform(new StringDecoder())
     .transform(new LineTransformer());
 
-  var stage = 0;
-  var subStage = 0;
-  stream.listen((line) {
-      if (stage == 0) {
-        if (subStage == 0) {
-          Expect.equals("Line1", line);
-          subStage++;
-        } else if (subStage == 1) {
-          Expect.equals("Line2", line);
-          subStage++;
-        } else if (subStage == 2) {
-          Expect.equals("Line3", line);
-          subStage = 0;
-          stage++;
-          controller.add("ne4\n".codeUnits);
-        } else {
-          Expect.fail("Stage 0 failed");
-        }
-      } else if (stage == 1) {
-        if (subStage == 0) {
-          Expect.equals("Line4", line);
-          subStage = 0;
-          stage++;
-          controller.add("\n\n\r\n\r\n\r\r".codeUnits);
-        } else {
-          Expect.fail("Stage 1 failed");
-        }
-      } else if (stage == 2) {
-        if (subStage < 4) {
-          // Expect 5 empty lines. As long as the stream is not closed the
-          // final \r cannot be interpreted as a end of line.
-          Expect.equals("", line);
-          subStage++;
-        } else if (subStage == 4) {
-          Expect.equals("", line);
-          subStage = 0;
-          stage++;
-          controller.close();
-        } else {
-          Expect.fail("Stage 2 failed");
-        }
-      } else if (stage == 3) {
-        if (subStage == 0) {
-          Expect.equals("", line);
-          stage++;
-        } else {
-          Expect.fail("Stage 3 failed");
-        }
-      }
-    }, onDone: () {
-      Expect.equals(4, stage);
-      Expect.equals(0, subStage);
-    });
+  var expectedLines = ['Line1', 'Line2','Line3', 'Line4',
+                       '', '', '', '', '', '',
+                       'Line5', 'Line6'];
 
+  var index = 0;
+
+  stream.listen((line) {
+    Expect.equals(expectedLines[index++], line);
+  });
+
+  // Note: codeUnits is fine. Text is ASCII.
   controller.add("Line1\nLine2\r\nLine3\rLi".codeUnits);
+  controller.add("ne4\n".codeUnits);
+  controller.add("\n\n\r\n\r\n\r\r".codeUnits);
+  controller.add("Line5\r".codeUnits);
+  controller.add("\nLine6\n".codeUnits);
+  controller.close();
+  Expect.equals(expectedLines.length, index);
 }
 
 class TestException implements Exception {
   TestException();
 }
 
-testErrorHandler() {
+void testErrorHandler() {
   var controller = new StreamController(sync: true);
   var errors = 0;
   var stream = controller.stream
@@ -205,7 +175,7 @@
   controller.close();
 }
 
-testLatin1EncoderError() {
+void testLatin1EncoderError() {
   List<int> data = [0x01,
                     0x7f,
                     0x44, 0x61, 0x72, 0x74,
@@ -226,13 +196,3 @@
     });
 
 }
-
-main() {
-  testUtf8();
-  testLatin1();
-  testAscii();
-  testReadLine1();
-  testReadLine2();
-  testErrorHandler();
-  testLatin1EncoderError();
-}
diff --git a/tests/standalone/io/user_certificate_test.dart b/tests/standalone/io/user_certificate_test.dart
new file mode 100644
index 0000000..c44ca96
--- /dev/null
+++ b/tests/standalone/io/user_certificate_test.dart
@@ -0,0 +1,116 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies the SecureSocket functions addCertificate,
+// importCertificatesWithPrivateKeys, changeTrust, getCertificate, and
+// removeCertificate.
+
+// It loads a copy of the test certificate database,
+// removes all certificates and keys, then imports the certificates and keys
+// again.  Then it runs a secure server, using the user certificate (a
+// certificate with private key), and starts client processes that use
+// addCertificate to trust the certificate that signed the server's certificate.
+// The clients then test that they can successfully connect to the server.
+
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+import "dart:io";
+import "dart:async";
+
+void main() {
+  Directory tempDirectory = new Directory('').createTempSync();
+  String scriptDirectory = dirname(Platform.script);
+  String database = join(scriptDirectory, 'pkcert');
+  String serverDatabase = join(tempDirectory.path, 'server');
+  String clientDatabase = join(tempDirectory.path, 'client');
+  new Directory(serverDatabase).createSync();
+  new Directory(clientDatabase).createSync();
+
+  cleanUp() {
+    if (Platform.isWindows) {
+      // Delay directory deletion until after this script exits.
+      // The certificate database files are locked until then.
+      Process.start('start',  // Starts a detatched process.
+                    [Platform.executable,
+                     join(scriptDirectory, 'delete_a_directory_later.dart'),
+                     tempDirectory.path],
+                     runInShell: true);
+    } else {
+      tempDirectory.delete(recursive: true);
+    }
+  }
+
+  Future.wait([
+      copyFileToDirectory(join(database, 'cert9.db'), serverDatabase),
+      copyFileToDirectory(join(database, 'key4.db'), serverDatabase),
+      copyFileToDirectory(join(database, 'cert9.db'), clientDatabase),
+      copyFileToDirectory(join(database, 'key4.db'), clientDatabase),
+  ]).then((_) {
+    SecureSocket.initialize(database: serverDatabase,
+                            password: 'dartdart',
+                            readOnly: false);
+    for (var nickname in ['localhost_cert', 'myauthority_cert']) {
+      Expect.isNotNull(SecureSocket.getCertificate(nickname));
+      SecureSocket.removeCertificate(nickname);
+      Expect.isNull(SecureSocket.getCertificate(nickname));
+    }
+
+    var mycerts = new File(join(database, 'localhost.p12')).readAsBytesSync();
+    SecureSocket.importCertificatesWithPrivateKeys(mycerts, 'dartdart');
+
+    checkCertificate('localhost_cert', 'CN=localhost', 'CN=myauthority');
+    checkCertificate('myauthority_cert', 'CN=myauthority', 'CN=myauthority');
+
+    SecureSocket.removeCertificate('myauthority_cert');
+    return runServer().then((server) {
+      var tests = ['certificate_test_client.dart',
+                   'certificate_test_client_database.dart'];
+      return Future.wait(tests.map((test) =>
+          Process.run(Platform.executable,
+                      ['--checked',
+                       join(scriptDirectory, test),
+                       server.port.toString(),
+                       join(database, 'myauthority.pem'),
+                       clientDatabase])))
+      .then(verifyResults)
+      .whenComplete(server.close);
+    });
+  })
+  .whenComplete(cleanUp);
+}
+
+checkCertificate(nickname, subject, issuer) {
+  var cert = SecureSocket.getCertificate(nickname);
+  Expect.isTrue(cert is X509Certificate);
+  Expect.equals(subject, cert.subject);
+  Expect.equals(issuer, cert.issuer);
+}
+
+Future<SecureServerSocket> runServer() =>
+  SecureServerSocket.bind("localhost", 0, "localhost_cert")
+    .then((server) => server..listen((socket) => socket.pipe(socket)));
+
+verifyResults(results) => results.map(verifyResult);
+verifyResult(ProcessResult result) {
+  if (result.exitCode != 0 ||  !result.stdout.contains('SUCCESS')) {
+    print("Client failed with exit code ${result.exitCode}");
+    print("  stdout (expected \"SUCCESS\\n\"):");
+    print(result.stdout);
+    print("  stderr:");
+    print(result.stderr);
+    Expect.fail("Client failed");
+  }
+}
+
+Future copyFileToDirectory(String file, String directory) {
+  switch (Platform.operatingSystem) {
+    case 'linux':
+    case 'macos':
+      return Process.run('cp', [file, directory]);
+    case 'windows':
+      return Process.run('cmd.exe', ['/C', 'copy $file $directory']);
+    default:
+      Expect.fail('Unknown operating system ${Platform.operatingSystem}');
+  }
+}
diff --git a/tests/standalone/javascript_int_overflow_test.dart b/tests/standalone/javascript_int_overflow_test.dart
index 6e38da6..3a5b932 100644
--- a/tests/standalone/javascript_int_overflow_test.dart
+++ b/tests/standalone/javascript_int_overflow_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// VMOptions=--throw_on_javascript_int_overflow --optimization_counter_threshold=10
+// VMOptions=--throw_on_javascript_int_overflow --optimization_counter_threshold=10 --no-use-osr
 
 
 import "package:expect/expect.dart";
@@ -54,6 +54,26 @@
   return min_literal;
 }
 
+
+int doNotThrow1(a, b) {
+  return (a << b) & 0xFFFFFFFF;
+}
+
+int doNotThrow2(a, b) {
+  return (a << b) & 0xFFFFFFFF;
+}
+
+
+int doNotThrow3(a, b) {
+  return (a << b) & 0x7FFFFFFF;
+}
+
+
+int doNotThrow4(a, b) {
+  return (a << b) & 0x7FFFFFFF;
+}
+
+
 // We don't test for the _JavascriptIntegerOverflowError since it's not visible.
 // It should not be visible since it doesn't exist on dart2js.
 bool isJavascriptIntError(e) =>
@@ -116,4 +136,16 @@
 
   Expect.throws(max_add_throws, isJavascriptIntError);
   Expect.throws(min_sub_throws, isJavascriptIntError);
+
+  for (int i = 0; i < 20; i++) {
+    Expect.equals(0xAFAFA000, doNotThrow1(0xFAFAFA, 12));
+    Expect.equals(0x2FAFA000, doNotThrow3(0xFAFAFA, 12));
+    Expect.equals(0xABABA000, doNotThrow2(0xFAFAFAABABA, 12));
+    Expect.equals(0x2BABA000, doNotThrow4(0xFAFAFAABABA, 12));
+  }
+  for (int i = 0; i < 20; i++) {
+    Expect.equals(0xABABA000, doNotThrow1(0xFAFAFAABABA, 12));
+    Expect.equals(0x2BABA000, doNotThrow3(0xFAFAFAABABA, 12));
+  }
+
 }
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index d16ecc4..25e362a4 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -11,16 +11,6 @@
 
 [ $runtime == vm ]
 package/package_isolate_test: Fail # http://dartbug.com/7520.
-vmservice/isolate_echo_test: Pass, Fail # Issue: 12294
-vmservice/isolate_list_test: Pass, Fail # Issue: 12294
-vmservice/isolate_stacktrace_command_test: Pass, Fail # Issue: 12294
-vmservice/unknown_isolate_command_test: Pass, Fail # Issue: 12294
-
-[ $runtime == vm && $system == windows ]
-vmservice/isolate_class_test: Pass, Fail # Issue: 12294
-vmservice/isolate_code_test: Pass, Fail # Issue: 12294
-vmservice/isolate_function_test: Pass, Fail # Issue: 12294
-vmservice/isolate_library_test: Pass, Fail # Issue: 12294
 
 [ $runtime == vm && $checked ]
 # These tests have type errors on purpose.
@@ -34,10 +24,12 @@
 io/file_fuzz_test: Skip
 io/directory_fuzz_test: Skip
 
-[ $runtime == vm && $system == windows ]
-vmservice/multiple_isolate_list_test: Fail, Pass # http://dartbug.com/12124
-
 [ $runtime == vm && $system == macos ]
+# These tests fail intermittently on MacOS due to an https request that
+# fails not completing the future it returns: Issue 12451
+io/https_unauthorized_test: Pass, Fail
+io/https_bad_certificate_test: Pass, Fail
+
 # This test fails with "Too many open files" on the Mac OS buildbot.
 # This is expected as MacOS by default runs with a very low number
 # of allowed open files ('ulimit -n' says something like 256).
@@ -161,17 +153,18 @@
 out_of_memory_test: Skip # passes on Mac, crashes on Linux
 oom_error_stacktrace_test: Skip # Fails on Linux
 io/web_socket_ping_test: Skip # TODO(ajohnsen): Timeout issue
+io/test_runner_test: Pass, Fail # Issue 12413
 
-[ $arch == simarm ]
-io/test_runner_test: Pass, Fail # Issue: 12239
-
-[ $arch == mips ]
-*: Skip
-
-[ $arch == simmips ]
+[ $arch == simmips || $arch == mips ]
 io/file_fuzz_test: Pass, Timeout
 io/web_socket_test: Pass, Slow
 io/http_server_response_test: Pass, Slow
 out_of_memory_test: Skip # passes on Mac, crashes on Linux
 oom_error_stacktrace_test: Skip # Fails on Linux
 io/web_socket_ping_test: Skip # TODO(ajohnsen): Timeout issue
+
+[ $arch == mips ]
+io/test_extension_test: Fail
+io/test_extension_fail_test: Fail
+io/dart_std_io_pipe_test: Fail
+io/file_read_special_device_test: Fail
diff --git a/tools/VERSION b/tools/VERSION
index 9112db6..5265791 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 6
-BUILD 17
-PATCH 4
+BUILD 18
+PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 82eafe2..79e538c 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -121,7 +121,7 @@
   fyi_supported_platforms = {
     'linux': [],
     'mac': [],
-    'windows': []
+    'windows': ['ie9']
   }
 
   if (runtime in supported_platforms[system]):
diff --git a/tools/dom/docs/docs.json b/tools/dom/docs/docs.json
index eb0de65..3299577 100644
--- a/tools/dom/docs/docs.json
+++ b/tools/dom/docs/docs.json
@@ -600,8 +600,10 @@
           "   * This call is used in conjunction with [open]:",
           "   *",
           "   *     var request = new HttpRequest();",
-          "   *     request.open('GET', 'http://dartlang.org')",
-          "   *     request.onLoad.listen((event) => print('Request complete'));",
+          "   *     request.open('GET', 'http://dartlang.org');",
+          "   *     request.onLoad.listen((event) => print(",
+          "   *         'Request complete ${event.target.reponseText}'));",
+          "   *     request.send();",
           "   *",
           "   * is the (more verbose) equivalent of",
           "   *",
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index 52d1de8..0692740 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -93,6 +93,9 @@
     # Group overloaded operations by name.
     self._AddRenamedOverloads(interface)
     operationsByName = self._OperationsByName(interface)
+    if self.OmitOperationOverrides():
+      self._RemoveShadowingOperationsWithSameSignature(operationsByName,
+          interface)
 
     # Generate operations.
     for id in sorted(operationsByName.keys()):
@@ -121,6 +124,10 @@
       # Group overloaded operations by name.
       operationsByName =self._OperationsByName(parent_interface)
 
+      if self.OmitOperationOverrides():
+        self._RemoveShadowingOperationsWithSameSignature(operationsByName,
+            interface)
+
       # Generate operations.
       for id in sorted(operationsByName.keys()):
         if not any(op.id == id for op in interface.operations):
@@ -129,6 +136,21 @@
           self.SecondaryContext(parent_interface)
           self.AddOperation(info)
 
+  def _RemoveShadowingOperationsWithSameSignature(self, operationsByName,
+      interface):
+    if not interface.parents:
+      return
+
+    parent = self._database.GetInterface(interface.parents[0].type.id)
+    if parent == self._interface or parent == interface:
+      return
+    for operation in parent.operations:
+      if operation.id in operationsByName:
+        operations = operationsByName[operation.id]
+        for existing_operation in operations:
+          if existing_operation.SameSignatureAs(operation):
+            del operationsByName[operation.id]
+
   def _AddRenamedOverloads(self, interface):
     """The IDL has a number of functions with the same name but that accept
     different types. This is fine for JavaScript, but results in vague type
@@ -201,6 +223,9 @@
       operationsByName.setdefault(name, []).append(operation)
     return operationsByName
 
+  def OmitOperationOverrides(self):
+    return False
+
   def AddConstant(self, constant):
     const_name = self._renamer.RenameMember(
         self._interface.id, constant, constant.id, 'get:', dartify_name=False)
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 73e10c4..23882c6 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -40,6 +40,7 @@
     'FileWriterCallback': '_FileWriterCallback',
     'HTMLDocument' : 'HtmlDocument',
     'IDBFactory': 'IdbFactory', # Manual to avoid name conflicts.
+    'Key': 'CryptoKey',
     'NamedNodeMap': '_NamedNodeMap',
     'NavigatorUserMediaErrorCallback': '_NavigatorUserMediaErrorCallback',
     'NavigatorUserMediaSuccessCallback': '_NavigatorUserMediaSuccessCallback',
@@ -514,10 +515,12 @@
     'Document.linkColor',
     'Document.location',
     'Document.open',
+    'Document.register',
     'Document.set:domain',
     'Document.vlinkColor',
     'Document.webkitCurrentFullScreenElement',
     'Document.webkitFullScreenKeyboardInputAllowed',
+    'Document.webkitRegister',
     'Document.write',
     'Document.writeln',
     'Document.xmlStandalone',
diff --git a/tools/dom/scripts/idlnode.py b/tools/dom/scripts/idlnode.py
index 5fc3d22..9957b35 100755
--- a/tools/dom/scripts/idlnode.py
+++ b/tools/dom/scripts/idlnode.py
@@ -496,6 +496,10 @@
   def _extra_repr(self):
     return [self.arguments]
 
+  def SameSignatureAs(self, operation):
+    if self.type != operation.type:
+      return False
+    return [a.type for a in self.arguments] == [a.type for a in operation.arguments]
 
 class IDLAttribute(IDLMember):
   """IDLNode specialization for 'attribute type name' declarations."""
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index b889489..5133ef6 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -925,6 +925,9 @@
   def RootClassName(self):
     return 'Interceptor'
 
+  def OmitOperationOverrides(self):
+    return True
+
   def EmitOperation(self, info, html_name):
     """
     Arguments:
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 0bf38cd..f9809eb 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -351,6 +351,7 @@
     if self._interface_type_info.custom_to_native():
       return_type = 'PassRefPtr<NativeType>'
       to_native_body = ';'
+      to_native_arg_body = ';'
     else:
       return_type = 'NativeType*'
       to_native_body = emitter.Format(
@@ -359,6 +360,12 @@
           '        return DartDOMWrapper::unwrapDartWrapper<Dart$INTERFACE>(handle, exception);\n'
           '    }',
           INTERFACE=self._interface.id)
+      to_native_arg_body = emitter.Format(
+          '\n'
+          '    {\n'
+          '        return DartDOMWrapper::unwrapDartWrapper<Dart$INTERFACE>(args, index, exception);\n'
+          '    }',
+          INTERFACE=self._interface.id)
 
     to_native_emitter.Emit(
         '    static $RETURN_TYPE toNative(Dart_Handle handle, Dart_Handle& exception)$TO_NATIVE_BODY\n'
@@ -366,9 +373,18 @@
         '    static $RETURN_TYPE toNativeWithNullCheck(Dart_Handle handle, Dart_Handle& exception)\n'
         '    {\n'
         '        return Dart_IsNull(handle) ? 0 : toNative(handle, exception);\n'
+        '    }\n'
+        '\n'
+        '    static $RETURN_TYPE toNative(Dart_NativeArguments args, int index, Dart_Handle& exception)$TO_NATIVE_ARG_BODY\n'
+        '\n'
+        '    static $RETURN_TYPE toNativeWithNullCheck(Dart_NativeArguments args, int index, Dart_Handle& exception)\n'
+        '    {\n'
+        '        // toNative accounts for Null objects also.\n'
+        '        return toNative(args, index, exception);\n'
         '    }\n',
         RETURN_TYPE=return_type,
         TO_NATIVE_BODY=to_native_body,
+        TO_NATIVE_ARG_BODY=to_native_arg_body,
         INTERFACE=self._interface.id)
 
     to_dart_emitter = emitter.Emitter()
@@ -882,10 +898,10 @@
       if type_info.pass_native_by_ref():
         invocation_template =\
             '        $TYPE $ARGUMENT_NAME;\n'\
-            '        $CLS::$FUNCTION(Dart_GetNativeArgument(args, $INDEX), $ARGUMENT_NAME, exception);\n'
+            '        $CLS::$FUNCTION(args, $INDEX, $ARGUMENT_NAME, exception);\n'
       else:
         invocation_template =\
-            '        $TYPE $ARGUMENT_NAME = $CLS::$FUNCTION(Dart_GetNativeArgument(args, $INDEX), exception);\n'
+            '        $TYPE $ARGUMENT_NAME = $CLS::$FUNCTION(args, $INDEX, exception);\n'
       body_emitter.Emit(
           '\n' +
           invocation_template +
@@ -955,6 +971,11 @@
         set_return_value = 'Dart_SetIntegerReturnValue(args, %s)' % (value_expression)
       elif return_type_info.dart_type() == 'double':
         set_return_value = 'Dart_SetDoubleReturnValue(args, %s)' % (value_expression)
+      elif return_type_info.dart_type() == 'String':
+        if ext_attrs and 'TreatReturnedNullStringAs' in ext_attrs:
+          set_return_value = 'DartUtilities::setDartStringReturnValueWithNullCheck(args, %s)' % (value_expression)
+        else:
+          set_return_value = 'DartUtilities::setDartStringReturnValue(args, %s)' % (value_expression)
       else:
         to_dart_conversion = return_type_info.to_dart_conversion(value_expression, self._interface.id, ext_attrs)
         set_return_value = 'Dart_SetReturnValue(args, %s)' % (to_dart_conversion)
diff --git a/tools/dom/src/KeyboardEventStream.dart b/tools/dom/src/KeyboardEventStream.dart
index 2e838d1..4d01f61 100644
--- a/tools/dom/src/KeyboardEventStream.dart
+++ b/tools/dom/src/KeyboardEventStream.dart
@@ -315,7 +315,7 @@
         !_firesKeyPressEvent(event)) {
       // Some browsers have quirks not firing keypress events where all other
       // browsers do. This makes them more consistent.
-      processKeyPress(event);
+      processKeyPress(e);
     }
     _keyDownList.add(event);
     _dispatch(event);
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index ad04f3f..8cdf24d 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -194,6 +194,38 @@
   // TODO(jacobr): we need a failsafe way to determine that a Node is really a
   // DOM node rather than just a class that extends Node.
   static bool isNode(obj) => obj is Node;
+
+  static void register(String tag, Type type) {
+    // TODO(vsm): Move these checks into native code.
+    if (type == null) {
+      throw new UnsupportedError("Invalid null type.");
+    }
+    ClassMirror cls = reflectClass(type);
+    LibraryMirror lib = cls.owner;
+    String libName = lib.uri.toString();
+    if (libName.startsWith('dart:')) {
+      throw new UnsupportedError("Invalid custom element from $libName.");
+    }
+    ClassMirror superClass = cls.superclass;
+
+    Symbol objectName = reflectClass(Object).qualifiedName;
+    bool isRoot(ClassMirror cls) =>
+      cls == null || cls.qualifiedName == objectName;
+    Symbol elementName = reflectClass(Element).qualifiedName;
+    bool isElement(ClassMirror cls) =>
+      cls != null && cls.qualifiedName == elementName;
+
+    while(!isRoot(superClass) && !isElement(superClass)) {
+      superClass = superClass.superclass;
+    }
+
+    if (isRoot(superClass)) {
+      throw new UnsupportedError("Invalid custom element doesn't inherit from Element.");
+    }
+    _register(tag, type);
+  }
+
+  static void _register(String tag, Type type) native "Utils_register";
 }
 
 class _NPObject extends NativeFieldWrapperClass1 {
diff --git a/tools/dom/templates/html/dartium/cpp_callback_header.template b/tools/dom/templates/html/dartium/cpp_callback_header.template
index 30f3ec3..285b523 100644
--- a/tools/dom/templates/html/dartium/cpp_callback_header.template
+++ b/tools/dom/templates/html/dartium/cpp_callback_header.template
@@ -29,6 +29,21 @@
             return 0;
         return create(object, exception);
     }
+
+    static PassRefPtr<NativeType> create(Dart_NativeArguments args, int idx, Dart_Handle& exception)
+    {
+        Dart_Handle object = Dart_GetNativeArgument(args, idx);
+        return create(object, exception);
+    }
+
+    static PassRefPtr<NativeType> createWithNullCheck(Dart_NativeArguments args, int idx, Dart_Handle& exception)
+    {
+        Dart_Handle object = Dart_GetNativeArgument(args, idx);
+        if (Dart_IsNull(object))
+            return 0;
+        return create(object, exception);
+    }
+
 $HANDLERS
 
 private:
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index dd64ae7..dded4de 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -20,6 +20,9 @@
 import 'dart:isolate';
 import 'dart:json' as json;
 import 'dart:math';
+// TODO(vsm): Remove this when we can do the proper checking in
+// native code for custom elements.
+import 'dart:mirrors';
 import 'dart:nativewrappers';
 import 'dart:typed_data';
 import 'dart:web_gl' as gl;
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 991fa21..cbea8c1 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -887,7 +887,7 @@
     } else if (JS('bool', '!!#.mozMatchesSelector', this)) {
       return JS('bool', '#.mozMatchesSelector(#)', this, selectors);
     } else if (JS('bool', '!!#.msMatchesSelector', this)) {
-      return matches = JS('bool', '#.msMatchesSelector(#)', this, selectors);
+      return JS('bool', '#.msMatchesSelector(#)', this, selectors);
     } else {
       throw new UnsupportedError("Not supported on this platform");
     }
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
index a75d1fc..227131a 100644
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
@@ -166,6 +166,16 @@
   @Experimental()
   String get visibilityState => $dom_webkitVisibilityState;
 
+  @Experimental
+$if DART2JS
+  void register(String tag, Type custom) {
+    throw new UnsupportedError("Custom DOM types not supported");
+  }
+$else
+  void register(String tag, Type custom) {
+    _Utils.register(tag, custom);
+  }
+$endif
 
 $if DART2JS
   @Creates('Null')  // Set from Dart code; does not instantiate a native type.
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index ba2445a..9997a19 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -54,7 +54,6 @@
             '-Wno-psabi', # suppresses va_list warning
             '-fno-strict-overflow',
           ],
-          'ldflags': ['-static'],
         }],
         ['_toolset=="host"', {
           'cflags': ['-m32', '-msse2'],
diff --git a/tools/publish_all_pkgs.py b/tools/publish_all_pkgs.py
index 6c302e2..81aab97 100644
--- a/tools/publish_all_pkgs.py
+++ b/tools/publish_all_pkgs.py
@@ -18,11 +18,11 @@
 import sys
 
 def Main(argv):
-  pkgs_to_publish = []
-  for name in os.listdir('pkg'):
-    if os.path.isdir(os.path.join('pkg', name)):
-      if (name != '.svn' and name != 'expect'):
-        pkgs_to_publish.append(os.path.join('pkg', name))
+  for pkgdir in ['pkg', 'pkg/third_party']:
+    for name in os.listdir(pkgdir):
+      if os.path.isdir(os.path.join(pkgdir, name)):
+        if (name != '.svn' and name != 'expect' and name != 'third_party'):
+          pkgs_to_publish.append(os.path.join(pkgdir, name))
 
   for pkg in pkgs_to_publish:
     print "\n\nPublishing %s:\n-------------------------------" % pkg
diff --git a/tools/publish_pkg.py b/tools/publish_pkg.py
index 55326ff..18f4cef 100755
--- a/tools/publish_pkg.py
+++ b/tools/publish_pkg.py
@@ -139,7 +139,7 @@
   if not os.path.exists(os.path.join(tmpDir, pkgName, 'LICENSE')):
     with open(os.path.join(tmpDir, pkgName, 'LICENSE'), 'w') as licenseFile:
       licenseFile.write(
-'''Copyright 2012, the Dart project authors. All rights reserved.
+'''Copyright 2013, the Dart project authors. All rights reserved.
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
 met:
diff --git a/tools/test.dart b/tools/test.dart
index 3147a36..e0a1617 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -158,7 +158,7 @@
     // There should not be more than one InternetExplorerDriver instance
     // running at a time. For details, see
     // http://code.google.com/p/selenium/wiki/InternetExplorerDriver.
-    if (conf['runtime'].startsWith('ie')) {
+    if (conf['runtime'].startsWith('ie') && !conf["use_browser_controller"]) {
       maxBrowserProcesses = 1;
     } else if (conf['runtime'].startsWith('safari') &&
                conf['use_browser_controller']) {
diff --git a/tools/testing/dart/browser_controller.dart b/tools/testing/dart/browser_controller.dart
index cde8b9d..6d55aee 100644
--- a/tools/testing/dart/browser_controller.dart
+++ b/tools/testing/dart/browser_controller.dart
@@ -54,13 +54,15 @@
       return new Chrome();
     } else if (name == 'safari') {
       return new Safari();
+    } else if (name.startsWith('ie')) {
+      return new IE();
     } else {
       throw "Non supported browser";
     }
   }
 
   static const List<String> SUPPORTED_BROWSERS =
-      const ['safari', 'ff', 'firefox', 'chrome'];
+    const ['safari', 'ff', 'firefox', 'chrome', 'ie9', 'ie10'];
 
   static const List<String> BROWSERS_WITH_WINDOW_SUPPORT =
       const ['safari', 'ff', 'firefox', 'chrome'];
@@ -144,7 +146,9 @@
           if (_cleanup != null) {
             _cleanup();
           }
-          doneCompleter.complete(exitCode);
+          doneCompleter.complete(true);
+        }).catchError((error) {
+          _logEvent("Error closing browsers: $error");
         });
       });
       return true;
@@ -347,6 +351,42 @@
   String toString() => "Chrome";
 }
 
+class IE extends Browser {
+
+  static const String binary =
+      "c:\\Program Files\\Internet Explorer\\iexplore.exe";
+
+  Future<String> getVersion() {
+    var args = ["query",
+                "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer",
+                "/v",
+                "version"];
+    return Process.run("reg", args).then((result) {
+      if (result.exitCode == 0) {
+        // The string we get back looks like this:
+        // HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer
+        //    version    REG_SZ    9.0.8112.16421
+        var findString = "REG_SZ";
+        var index = result.stdout.indexOf(findString);
+        if (index > 0) {
+          return result.stdout.substring(index + findString.length).trim();
+        }
+      }
+      return "Could not get the version of internet explorer";
+    });
+  }
+
+  Future<bool> start(String url) {
+    _logEvent("Starting ie browser on: $url");
+    return getVersion().then((version) {
+      _logEvent("Got version: $version");
+      return startBrowser(binary, [url]);
+    });
+  }
+  String toString() => "IE";
+}
+
+
 class AndroidChrome extends Browser {
   static const String viewAction = 'android.intent.action.VIEW';
   static const String mainAction = 'android.intent.action.MAIN';
@@ -609,7 +649,6 @@
 
   void handleResults(String browserId, String output, int testId) {
     var status = browserStatus[browserId];
-    DebugLogger.info("Handling result for browser ${browserId}");
     if (testCache.containsKey(testId)) {
       doubleReportingTests.add(testId);
       return;
@@ -631,12 +670,10 @@
         throw("This should never happen, wrong test id");
       }
       testCache[testId] = status.currentTest.url;
-      DebugLogger.info("Size of output for test $testId : ${output.length}");
       Stopwatch watch = new Stopwatch()..start();
       status.currentTest.doneCallback(output,
                                       status.currentTest.stopwatch.elapsed);
       watch.stop();
-      DebugLogger.info("Handling of test $testId took : ${watch.elapsed}");
       status.lastTest = status.currentTest;
       status.currentTest = null;
     } else {
@@ -652,7 +689,6 @@
   void handleTimeout(BrowserTestingStatus status) {
     // We simply kill the browser and starts up a new one!
     // We could be smarter here, but it does not seems like it is worth it.
-    DebugLogger.info("Handling timeout for browser ${status.browser.id}");
     status.timeout = true;
     timedOut.add(status.currentTest.url);
     var id = status.browser.id;
@@ -701,8 +737,6 @@
     if (testQueue.isEmpty) return null;
     var status = browserStatus[browserId];
     if (status == null) return null;
-    DebugLogger.info("Handling getNext for browser "
-                     "${browserId} timeout status: ${status.timeout}");
 
     // We are currently terminating this browser, don't start a new test.
     if (status.timeout) return null;
@@ -801,10 +835,13 @@
     return HttpServer.bind(local_ip, 0).then((createdServer) {
       httpServer = createdServer;
       void handler(HttpRequest request) {
-        DebugLogger.info("Handling request to: ${request.uri.path}");
+        // Don't allow caching of resources from the browser controller, i.e.,
+        // we don't want the browser to cache the result of getNextTest.
+        request.response.headers.set("Cache-Control",
+                                     "no-cache, no-store, must-revalidate");
         if (request.uri.path.startsWith(reportPath)) {
           var browserId = request.uri.path.substring(reportPath.length + 1);
-          var testId = 
+          var testId =
               int.parse(request.uri.queryParameters["id"].split("=")[1]);
           handleReport(request, browserId, testId);
           // handleReport will asynchroniously fetch the data and will handle
@@ -819,14 +856,11 @@
           var browserId = request.uri.path.substring(nextTestPath.length + 1);
           textResponse = getNextTest(browserId);
         } else {
-          DebugLogger.info("Handling non standard request to: "
-                           "${request.uri.path}");
+          // /favicon.ico requests
         }
         request.response.write(textResponse);
         request.listen((_) {}, onDone: request.response.close);
-        request.response.done.then((_) {
-          DebugLogger.info("Done handling request to: ${request.uri.path}");
-        }).catchError((error) {
+        request.response.done.catchError((error) {
           if (!underTermination) {
             print("URI ${request.uri}");
             print("Textresponse $textResponse");
@@ -851,7 +885,6 @@
           }, onDone: () {
               String back = buffer.toString();
               request.response.headers.set("Access-Control-Allow-Origin", "*");
-
               request.response.done.catchError((error) {
                 DebugLogger.error("Error getting error from browser"
                                   "on uri ${request.uri.path}: $error");
@@ -876,7 +909,6 @@
         String back = buffer.toString();
         request.response.close();
         testDoneCallBack(browserId, back, testId);
-        DebugLogger.info("Done handling request to: ${request.uri.path}");
       }, onError: (error) { print(error); });
   }
 
@@ -917,11 +949,11 @@
     function startTesting() {
       var number_of_tests = 0;
       var current_id;
-      var last_reported_id;
+      var next_id;
+      // Describes a state where we are currently fetching the next test
+      // from the server. We use this to never double request tasks.
+      var test_completed = true;
       var testing_window;
-      // We use this to determine if we did actually get back a start event
-      // from the test we just loaded.
-      var did_start = false;
 
       var embedded_iframe = document.getElementById('embedded_iframe');
       var use_iframe = ${useIframe};
@@ -936,15 +968,11 @@
               // Don't do anything, we will be killed shortly.
             } else {
               var elapsed = new Date() - start;
-              // TODO(ricow): Do something more clever here.
-              if (nextTask != undefined) alert('This is really bad');
               // The task is send to us as:
               // URL#ID
               var split = this.responseText.split('#');
               var nextTask = split[0];
-              current_id = split[1];
-              reportError('Done getting task : ' + elapsed);
-              did_start = false;
+              next_id = split[1];
               run(nextTask);
             }
           } else {
@@ -954,8 +982,8 @@
       }
 
       function getNextTask() {
-        var elapsed = new Date() - start;
-        reportError('Getting task at: ' + elapsed);
+        // Until we have the next task we set the current_id to a specific
+        // negative value.
         var client = new XMLHttpRequest();
         client.onreadystatechange = newTaskHandler;
         client.open('GET', '$nextTestPath/$browserId');
@@ -1001,36 +1029,31 @@
 
       function reportMessage(msg) {
         if (msg == 'STARTING') {
-          did_start = true;
+          test_completed = false;
+          current_id = next_id;
           return;
         }
-        var client = new XMLHttpRequest();
+
+        var is_double_report = test_completed;
+        test_completed = true;
+
         function handleReady() {
           if (this.readyState == this.DONE) {
             if (this.status == 200) {
-              if (last_reported_id != current_id && did_start) {
-                var elapsed = new Date() - start;
-                reportError('Done sending results at: ' + elapsed);
+              if (!is_double_report) {
                 getNextTask();
-                last_reported_id = current_id;
               }
             } else {
               reportError('Error sending result to server');
             }
           }
         }
+        var client = new XMLHttpRequest();
         client.onreadystatechange = handleReady;
-        // If did_start is false it means that we did actually set the url on
-        // the testing_window, but this is a report left in the event loop or
-        // a callback because the page did not load yet.
-        // In both cases this is a double report from the last test.
-        var posting_id = did_start ? current_id : last_reported_id;
-        client.open('POST', '$reportPath/${browserId}?id=' + posting_id);
+        client.open('POST', '$reportPath/${browserId}?id=' + current_id);
         client.setRequestHeader('Content-type',
                                 'application/x-www-form-urlencoded');
         client.send(msg);
-        var elapsed = new Date() - start;
-        reportError('Sending results at: ' + elapsed);
       }
 
       function messageHandler(e) {
diff --git a/tools/testing/dart/browser_test.dart b/tools/testing/dart/browser_test.dart
index 3d9dbd9..646115b 100644
--- a/tools/testing/dart/browser_test.dart
+++ b/tools/testing/dart/browser_test.dart
@@ -25,7 +25,8 @@
   <script type="text/javascript"
           src="/root_dart/pkg/unittest/lib/test_controller.js">
   </script>
-  <script type="$scriptType" src="$sourceScript" onerror="externalError(null)">
+  <script type="$scriptType" src="$sourceScript" onerror="externalError(null)"
+          defer>
   </script>
   <script type="text/javascript"
           src="/root_dart/pkg/browser/lib/dart.js"></script>
@@ -46,7 +47,7 @@
   <script type="text/javascript">
     if (navigator.webkitStartDart) navigator.webkitStartDart();
   </script>
-  <script type="$scriptType" src="$sourceScript"></script>
+  <script type="$scriptType" src="$sourceScript" defer></script>
 </body>
 </html>
 """;
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index f66c485..fb1b11f 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -100,7 +100,7 @@
               'arch',
               'The architecture to run tests for',
               ['-a', '--arch'],
-              ['all', 'ia32', 'x64', 'simarm', 'simmips', 'arm'],
+              ['all', 'ia32', 'x64', 'simarm', 'simmips', 'arm', 'mips'],
               'ia32'),
           new _TestOptionSpecification(
               'system',
@@ -669,6 +669,10 @@
             timeout *= 4;
           } else if (configuration['arch'] == 'arm') {
             timeout *= 4;
+          } else if (configuration['arch'] == 'simmips') {
+            timeout *= 4;
+          } else if (configuration['arch'] == 'mips') {
+            timeout *= 4;
           }
           if (configuration['mode'] == 'debug') {
             timeout *= 2;
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 1012082..fbb1de1 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -30,6 +30,9 @@
 const int CRASHING_BROWSER_EXITCODE = -10;
 const int SLOW_TIMEOUT_MULTIPLIER = 4;
 
+const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display';
+const MESSAGE_FAILED_TO_RUN_COMMAND = 'Failed to run command. return code=1';
+
 typedef void TestCaseEvent(TestCase testCase);
 typedef void ExitCodeEvent(int exitCode);
 typedef void EnqueueMoreWork(ProcessQueue queue);
@@ -58,8 +61,8 @@
   /** Environment for the command */
   Map<String, String> environmentOverrides;
 
-  /** Number of times this command can be retried */
-  int get numRetries => 0;
+  /** Number of times this command *can* be retried */
+  int get maxNumRetries => 2;
 
   // We compute the Command.hashCode lazily and cache it here, since it might
   // be expensive to compute (and hashCode is called often).
@@ -295,8 +298,7 @@
         expectedOutputPath.toString() == other.expectedOutputPath.toString();
   }
 
-  // FIXME(kustermann): Remove this once we're stable
-  int get numRetries => 2;
+  int get maxNumRetries => 3;
 }
 
 class BrowserTestCommand extends Command {
@@ -324,9 +326,6 @@
         browser == other.browser &&
         url == other.url;
   }
-
-  // FIXME(kustermann): Remove this once we're stable
-  int get numRetries => 2;
 }
 
 class SeleniumTestCommand extends Command {
@@ -354,9 +353,6 @@
         browser == other.browser &&
         url == other.url;
   }
-
-  // FIXME(kustermann): Remove this once we're stable
-  int get numRetries => 2;
 }
 
 class AnalysisCommand extends Command {
@@ -555,7 +551,7 @@
   }
 
   bool get isFinished {
-    return !lastCommandOutput.successfull ||
+    return !lastCommandOutput.successful ||
            commands.length == commandOutputs.length;
   }
 }
@@ -599,7 +595,7 @@
 
   bool get canRunDependendCommands;
 
-  bool get successfull; // otherwise we might to retry running
+  bool get successful; // otherwise we might to retry running
 
   Duration get time;
 
@@ -682,7 +678,7 @@
     return !hasTimedOut && exitCode == 0;
   }
 
-  bool get successfull {
+  bool get successful {
     // FIXME(kustermann): We may need to change this
     return !hasTimedOut && exitCode == 0;
   }
@@ -726,6 +722,8 @@
     }
   }
 
+  bool get successful => canRunDependendCommands;
+
   bool get canRunDependendCommands {
     // We cannot rely on the exit code of content_shell as a method to determine
     // if we were successful or not.
@@ -754,8 +752,8 @@
     for (String line in stderrLines) {
       // TODO(kustermann,ricow): Issue: 7564
       // This seems to happen quite frequently, we need to figure out why.
-      if (line.contains('Gtk-WARNING **: cannot open display') ||
-          line.contains('Failed to run command. return code=1')) {
+      if (line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) ||
+          line.contains(MESSAGE_FAILED_TO_RUN_COMMAND)) {
         return true;
       }
     }
@@ -1772,7 +1770,7 @@
 
     Future<CommandOutput> runCommand(int retriesLeft) {
       return _runCommand(command, timeout).then((CommandOutput output) {
-        if (!output.canRunDependendCommands && retriesLeft > 0) {
+        if (retriesLeft > 0 && shouldRetryCommand(output)) {
           DebugLogger.warning("Rerunning Command: ($retriesLeft "
                               "attempt(s) remains) [cmd: $command]");
           return runCommand(retriesLeft - 1);
@@ -1781,7 +1779,7 @@
         }
       });
     }
-    return runCommand(command.numRetries);
+    return runCommand(command.maxNumRetries);
   }
 
   Future<CommandOutput> _runCommand(Command command, int timeout) {
@@ -1849,7 +1847,9 @@
     if (_browserTestRunners[browser] == null) {
       var testRunner =
         new BrowserTestRunner(local_ip, browser, num_browsers);
-      testRunner.logger = DebugLogger.info;
+      if (globalConfiguration['verbose']) {
+        testRunner.logger = DebugLogger.info;
+      }
       _browserTestRunners[browser] = testRunner;
       return testRunner.start().then((started) {
         if (started) {
@@ -1909,6 +1909,50 @@
   }
 }
 
+bool shouldRetryCommand(CommandOutput output) {
+  var command = output.command;
+
+  if (!output.successful) {
+    List<String> stdout, stderr;
+
+    decodeOutput() {
+      if (stdout == null && stderr == null) {
+        stdout = decodeUtf8(output.stderr).split("\n");
+        stderr = decodeUtf8(output.stderr).split("\n");
+      }
+    }
+
+    if (io.Platform.operatingSystem == 'linux') {
+      decodeOutput();
+      // No matter which command we ran: If we get failures due to the
+      // "xvfb-run" issue 7564, try re-running the test.
+      bool containsFailureMsg(String line) {
+        return line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) ||
+               line.contains(MESSAGE_FAILED_TO_RUN_COMMAND);
+      }
+      if (stdout.any(containsFailureMsg) || stderr.any(containsFailureMsg)) {
+        return true;
+      }
+    }
+
+    if (command is BrowserTestCommand) {
+      // We do not re-run tests on the new browser controller, since it should
+      // not be as flaky as selenium.
+      return false;
+    } else if (command is SeleniumTestCommand) {
+      // Selenium tests can be flaky. Try re-running.
+      return true;
+    } else if (command is ContentShellCommand) {
+      // FIXME(kustermann): Remove this condition once we figured out why
+      // content_shell is sometimes not able to fetch resources from the
+      // HttpServer on windows.
+      // TODO(kustermann): Don't blindly re-run DRT tests on windows but rather
+      // check if the stderr/stdout indicates that we actually have this issue.
+      return io.Platform.operatingSystem == 'windows';
+    }
+  }
+  return false;
+}
 
 /*
  * [TestCaseCompleter] will listen for