[roll] Update third-party dart packages

Change-Id: I18c284b0503b26e99e66b9434a0775857d8f8c1f
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/dart-pkg/+/438688
Reviewed-by: GI Roller <global-integration-roller@fuchsia-infra.iam.gserviceaccount.com>
Commit-Queue: GI Roller <global-integration-roller@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/checked_yaml/BUILD.gn b/checked_yaml/BUILD.gn
new file mode 100644
index 0000000..c7d2b6d
--- /dev/null
+++ b/checked_yaml/BUILD.gn
@@ -0,0 +1,21 @@
+# This file is generated by importer.py for checked_yaml-1.0.2
+
+import("//build/dart/dart_library.gni")
+
+dart_library("checked_yaml") {
+  package_name = "checked_yaml"
+
+  language_version = "2.3"
+
+  disable_analysis = true
+
+  deps = [
+    "//third_party/dart-pkg/pub/source_span",
+    "//third_party/dart-pkg/pub/json_annotation",
+    "//third_party/dart-pkg/pub/yaml",
+  ]
+
+  sources = [
+    "checked_yaml.dart",
+  ]
+}
diff --git a/checked_yaml/LICENSE b/checked_yaml/LICENSE
new file mode 100644
index 0000000..f75d7c2
--- /dev/null
+++ b/checked_yaml/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2019, 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:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/checked_yaml/changelog.md b/checked_yaml/changelog.md
new file mode 100644
index 0000000..9b707b8
--- /dev/null
+++ b/checked_yaml/changelog.md
@@ -0,0 +1,12 @@
+## 1.0.2
+
+- Require at least Dart `2.3.0`.
+- Support the latest `package:json_annotation`.
+
+## 1.0.1
+
+- Fix readme.
+
+## 1.0.0
+
+- Initial release.
diff --git a/checked_yaml/dart_test.yaml b/checked_yaml/dart_test.yaml
new file mode 100644
index 0000000..1d7ac69
--- /dev/null
+++ b/checked_yaml/dart_test.yaml
@@ -0,0 +1,3 @@
+tags:
+  presubmit-only:
+    skip: "Should only be run during presubmit"
diff --git a/checked_yaml/example/example.dart b/checked_yaml/example/example.dart
new file mode 100644
index 0000000..7e9b820
--- /dev/null
+++ b/checked_yaml/example/example.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, 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:checked_yaml/checked_yaml.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'example.g.dart';
+
+@JsonSerializable(
+  anyMap: true,
+  checked: true,
+  disallowUnrecognizedKeys: true,
+  nullable: false,
+)
+class Configuration {
+  @JsonKey(required: true)
+  final String name;
+  @JsonKey(required: true)
+  final int count;
+
+  Configuration({this.name, this.count}) {
+    if (name.isEmpty) {
+      throw ArgumentError.value(name, 'name', 'Cannot be empty.');
+    }
+  }
+
+  factory Configuration.fromJson(Map json) => _$ConfigurationFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ConfigurationToJson(this);
+
+  @override
+  String toString() => 'Configuration: ${toJson()}';
+}
+
+void main(List<String> arguments) {
+  var sourcePathOrYaml = arguments.single;
+  String yamlContent;
+
+  if (FileSystemEntity.isFileSync(sourcePathOrYaml)) {
+    yamlContent = File(sourcePathOrYaml).readAsStringSync();
+  } else {
+    yamlContent = sourcePathOrYaml;
+    sourcePathOrYaml = null;
+  }
+
+  final config = checkedYamlDecode(
+      yamlContent, (m) => Configuration.fromJson(m),
+      sourceUrl: sourcePathOrYaml);
+  print(config);
+}
diff --git a/checked_yaml/example/example.g.dart b/checked_yaml/example/example.g.dart
new file mode 100644
index 0000000..854bcba
--- /dev/null
+++ b/checked_yaml/example/example.g.dart
@@ -0,0 +1,26 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'example.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Configuration _$ConfigurationFromJson(Map json) {
+  return $checkedNew('Configuration', json, () {
+    $checkKeys(json,
+        allowedKeys: const ['name', 'count'],
+        requiredKeys: const ['name', 'count']);
+    final val = Configuration(
+      name: $checkedConvert(json, 'name', (v) => v as String),
+      count: $checkedConvert(json, 'count', (v) => v as int),
+    );
+    return val;
+  });
+}
+
+Map<String, dynamic> _$ConfigurationToJson(Configuration instance) =>
+    <String, dynamic>{
+      'name': instance.name,
+      'count': instance.count,
+    };
diff --git a/checked_yaml/lib/checked_yaml.dart b/checked_yaml/lib/checked_yaml.dart
new file mode 100644
index 0000000..aabf357
--- /dev/null
+++ b/checked_yaml/lib/checked_yaml.dart
@@ -0,0 +1,152 @@
+// Copyright (c) 2019, 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:json_annotation/json_annotation.dart';
+import 'package:yaml/yaml.dart';
+
+/// Decodes [yamlContent] as YAML and calls [constructor] with the resulting
+/// [Map].
+///
+/// If there are errors thrown while decoding [yamlContent], if it is not a
+/// [Map] or if [CheckedFromJsonException] is thrown when calling [constructor],
+/// a [ParsedYamlException] will be thrown.
+///
+/// If [sourceUrl] is passed, it's used as the URL from which the YAML
+/// originated for error reporting. It can be a [String], a [Uri], or `null`.
+///
+/// If [allowNull] is `true`, a `null` value from [yamlContent] will be allowed
+/// and passed to [constructor]. [constructor], therefore, will need to handle
+/// `null` values.
+T checkedYamlDecode<T>(
+  String yamlContent,
+  T Function(Map) constructor, {
+  sourceUrl,
+  bool allowNull = false,
+}) {
+  allowNull ??= false;
+  YamlNode yaml;
+
+  try {
+    yaml = loadYamlNode(yamlContent, sourceUrl: sourceUrl);
+  } on YamlException catch (e) {
+    throw ParsedYamlException.fromYamlException(e);
+  }
+
+  Map map;
+  if (yaml is YamlMap) {
+    map = yaml;
+  } else if (allowNull && yaml is YamlScalar && yaml.value == null) {
+    // TODO(kevmoo): test this case!
+    map = null;
+  } else {
+    throw ParsedYamlException('Not a map', yaml);
+  }
+
+  try {
+    return constructor(map);
+  } on CheckedFromJsonException catch (e) {
+    throw toParsedYamlException(e);
+  }
+}
+
+/// Returns a [ParsedYamlException] for the provided [exception].
+///
+/// This function assumes `exception.map` is of type `YamlMap` from
+/// `package:yaml`. If not, you may provide an alternative via [exceptionMap].
+ParsedYamlException toParsedYamlException(
+  CheckedFromJsonException exception, {
+  YamlMap exceptionMap,
+}) {
+  final yamlMap = exceptionMap ?? exception.map as YamlMap;
+
+  final innerError = exception.innerError;
+
+  if (exception.badKey) {
+    final key = (innerError is UnrecognizedKeysException)
+        ? innerError.unrecognizedKeys.first
+        : exception.key;
+
+    final node = yamlMap.nodes.keys.singleWhere(
+        (k) => (k as YamlScalar).value == key,
+        orElse: () => yamlMap) as YamlNode;
+    return ParsedYamlException(
+      exception.message,
+      node,
+      innerError: exception,
+    );
+  } else {
+    final yamlValue = yamlMap.nodes[exception.key];
+
+    if (yamlValue == null) {
+      // TODO(kevmoo): test this case!
+      return ParsedYamlException(
+        exception.message,
+        yamlMap,
+        innerError: exception,
+      );
+    } else {
+      var message = 'Unsupported value for "${exception.key}".';
+      if (exception.message != null) {
+        message = '$message ${exception.message}';
+      }
+      return ParsedYamlException(
+        message,
+        yamlValue,
+        innerError: exception,
+      );
+    }
+  }
+}
+
+/// An exception thrown when parsing YAML that contains information about the
+/// location in the source where the exception occurred.
+class ParsedYamlException implements Exception {
+  /// Describes the nature of the parse failure.
+  final String message;
+
+  /// The node associated with this exception.
+  ///
+  /// May be `null` if there was an error decoding.
+  final YamlNode yamlNode;
+
+  /// If this exception was thrown as a result of another error,
+  /// contains the source error object.
+  final Object innerError;
+
+  ParsedYamlException(
+    this.message,
+    this.yamlNode, {
+    this.innerError,
+  })  : assert(message != null),
+        assert(yamlNode != null);
+
+  factory ParsedYamlException.fromYamlException(YamlException exception) =>
+      _WrappedYamlException(exception);
+
+  /// Returns [message] formatted with source information provided by
+  /// [yamlNode].
+  String get formattedMessage => yamlNode.span.message(message);
+
+  @override
+  String toString() => 'ParsedYamlException: $formattedMessage';
+}
+
+class _WrappedYamlException implements ParsedYamlException {
+  _WrappedYamlException(this.innerError);
+
+  @override
+  String get formattedMessage => innerError.span.message(innerError.message);
+
+  @override
+  final YamlException innerError;
+
+  @override
+  String get message => innerError.message;
+
+  @override
+  YamlNode get yamlNode => null;
+
+  @override
+  String toString() => 'ParsedYamlException: $formattedMessage';
+}
diff --git a/checked_yaml/mono_pkg.yaml b/checked_yaml/mono_pkg.yaml
new file mode 100644
index 0000000..1db1b96
--- /dev/null
+++ b/checked_yaml/mono_pkg.yaml
@@ -0,0 +1,19 @@
+# See https://github.com/dart-lang/mono_repo for details
+dart:
+- 2.3.0
+- dev
+
+stages:
+- analyzer_and_format:
+  - group:
+    - dartfmt
+    - dartanalyzer: --fatal-warnings --fatal-infos .
+    dart: [dev]
+  - group:
+    - dartanalyzer: --fatal-warnings .
+    dart: [2.3.0]
+
+- unit_test:
+  - test
+- ensure_build:
+  - test: --run-skipped -t presubmit-only test/ensure_build_test.dart
diff --git a/checked_yaml/pubspec.yaml b/checked_yaml/pubspec.yaml
new file mode 100644
index 0000000..a962f6e
--- /dev/null
+++ b/checked_yaml/pubspec.yaml
@@ -0,0 +1,22 @@
+name: checked_yaml
+version: 1.0.2
+author: Dart Team <misc@dartlang.org>
+description: >-
+  Generate more helpful exceptions when decoding YAML documents using
+  package:json_serializable and package:yaml.
+homepage: https://github.com/dart-lang/json_serializable
+environment:
+  sdk: '>=2.3.0 <3.0.0'
+
+dependencies:
+  json_annotation: '>=2.2.0 <4.0.0'
+  source_span: ^1.0.0
+  yaml: ^2.1.13
+
+dev_dependencies:
+  json_serializable: ^3.0.0
+  build_runner: ^1.0.0
+  build_verify: ^1.1.0
+  path: ^1.0.0
+  test: ^1.6.0
+  test_process: ^1.0.1
diff --git a/checked_yaml/readme.md b/checked_yaml/readme.md
new file mode 100644
index 0000000..0e60c0a
--- /dev/null
+++ b/checked_yaml/readme.md
@@ -0,0 +1,79 @@
+[![Pub Package](https://img.shields.io/pub/v/checked_yaml.svg)](https://pub.dev/packages/checked_yaml)
+
+`package:checked_yaml` provides a `checkedYamlDecode` function that wraps the
+the creation of classes annotated for [`package:json_serializable`] it helps
+provide more helpful exceptions when the provided YAML is not compatible with
+the target type.
+
+[`package:json_serializable`] can generate classes that can parse the
+[`YamlMap`] type provided by [`package:yaml`] when `anyMap: true` is specified
+for the class annotation. 
+
+```dart
+@JsonSerializable(
+  anyMap: true,
+  checked: true,
+  disallowUnrecognizedKeys: true,
+  nullable: false,
+)
+class Configuration {
+  @JsonKey(required: true)
+  final String name;
+  @JsonKey(required: true)
+  final int count;
+
+  Configuration({this.name, this.count}) {
+    if (name.isEmpty) {
+      throw ArgumentError.value(name, 'name', 'Cannot be empty.');
+    }
+  }
+
+  factory Configuration.fromJson(Map json) => _$ConfigurationFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ConfigurationToJson(this);
+
+  @override
+  String toString() => 'Configuration: ${toJson()}';
+}
+```
+
+When `checked: true` is set, exceptions thrown when decoding an instance from a
+`Map` are wrapped in a `CheckedFromJsonException`. The
+`checkedYamlDecode` function catches these exceptions and throws a
+`ParsedYamlException` which maps the exception to the location in the input
+YAML with the error.
+
+```dart
+void main(List<String> arguments) {
+  var sourcePathOrYaml = arguments.single;
+  String yamlContent;
+
+  if (FileSystemEntity.isFileSync(sourcePathOrYaml)) {
+    yamlContent = File(sourcePathOrYaml).readAsStringSync();
+  } else {
+    yamlContent = sourcePathOrYaml;
+    sourcePathOrYaml = null;
+  }
+
+  final config = checkedYamlDecode(
+      yamlContent, (m) => Configuration.fromJson(m),
+      sourceUrl: sourcePathOrYaml);
+  print(config);
+}
+```
+
+When parsing an invalid YAML file, an actionable error message is produced.
+
+```console
+$ dart example/example.dart '{"name": "", "count": 1}'
+Unhandled exception:
+ParsedYamlException: line 1, column 10: Unsupported value for "name". Cannot be empty.
+  ╷
+1 │ {"name": "", "count": 1}
+  │          ^^
+  ╵
+```
+
+[`package:json_serializable`]: https://pub.dev/packages/json_serializable
+[`package:yaml`]: https://pub.dev/packages/yaml
+[`YamlMap`]: https://pub.dev/documentation/yaml/latest/yaml/YamlMap-class.html
diff --git a/dds/BUILD.gn b/dds/BUILD.gn
index 3e7df37..54d1449 100644
--- a/dds/BUILD.gn
+++ b/dds/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for dds-1.4.1
+# This file is generated by importer.py for dds-1.4.0
 
 import("//build/dart/dart_library.gni")
 
diff --git a/dds/CHANGELOG.md b/dds/CHANGELOG.md
index f959b95..dcacb48 100644
--- a/dds/CHANGELOG.md
+++ b/dds/CHANGELOG.md
@@ -1,8 +1,3 @@
-# 1.4.1
-- Fixed issue where `evaluate` and `evaluateInFrame` requests were not being
-  forwarded to the VM service properly when no external compilation service
-  was registered.
-
 # 1.4.0
 - Added `done` property to `DartDevelopmentService`.
 - Throw `DartDeveloperServiceException` when shutdown occurs during startup.
diff --git a/dds/lib/src/expression_evaluator.dart b/dds/lib/src/expression_evaluator.dart
index 348d8f4..d514d60 100644
--- a/dds/lib/src/expression_evaluator.dart
+++ b/dds/lib/src/expression_evaluator.dart
@@ -11,18 +11,6 @@
   _ExpressionEvaluator(this.dds);
 
   Future<Map<String, dynamic>> execute(json_rpc.Parameters parameters) async {
-    _DartDevelopmentServiceClient externalClient =
-        dds.clientManager.findFirstClientThatHandlesService(
-      'compileExpression',
-    );
-    // If no compilation service is registered, just forward to the VM service.
-    if (externalClient == null) {
-      return await dds._vmServiceClient.sendRequest(
-        parameters.method,
-        parameters.value,
-      );
-    }
-
     final isolateId = parameters['isolateId'].asString;
     final expression = parameters['expression'].asString;
     Map<String, dynamic> buildScopeResponse;
@@ -68,11 +56,6 @@
         dds.clientManager.findFirstClientThatHandlesService(
       'compileExpression',
     );
-    if (externalClient == null) {
-      throw _RpcErrorCodes.buildRpcException(
-          _RpcErrorCodes.kExpressionCompilationError,
-          data: 'compileExpression service disappeared.');
-    }
 
     final compileParams = <String, dynamic>{
       'isolateId': isolateId,
@@ -87,11 +70,20 @@
     if (klass != null) {
       compileParams['klass'] = klass;
     }
+    // TODO(bkonyi): handle service disappeared case?
     try {
-      return (await externalClient.sendRequest(
-        'compileExpression',
-        compileParams,
-      ))['kernelBytes'];
+      if (externalClient != null) {
+        return (await externalClient.sendRequest(
+          'compileExpression',
+          compileParams,
+        ))['kernelBytes'];
+      } else {
+        // Fallback to compiling using the kernel service.
+        return (await dds._vmServiceClient.sendRequest(
+          '_compileExpression',
+          compileParams,
+        ))['kernelBytes'];
+      }
     } on json_rpc.RpcException catch (e) {
       throw _RpcErrorCodes.buildRpcException(
         _RpcErrorCodes.kExpressionCompilationError,
diff --git a/dds/pubspec.yaml b/dds/pubspec.yaml
index a7ae669..1874281 100644
--- a/dds/pubspec.yaml
+++ b/dds/pubspec.yaml
@@ -3,7 +3,7 @@
   A library used to spawn the Dart Developer Service, used to communicate with
   a Dart VM Service instance.
 
-version: 1.4.1
+version: 1.4.0
 
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds
 
diff --git a/file_testing/BUILD.gn b/file_testing/BUILD.gn
new file mode 100644
index 0000000..447f5e2
--- /dev/null
+++ b/file_testing/BUILD.gn
@@ -0,0 +1,22 @@
+# This file is generated by importer.py for file_testing-2.1.0
+
+import("//build/dart/dart_library.gni")
+
+dart_library("file_testing") {
+  package_name = "file_testing"
+
+  language_version = "2.1"
+
+  disable_analysis = true
+
+  deps = [
+    "//third_party/dart-pkg/pub/test_api",
+    "//third_party/dart-pkg/pub/meta",
+  ]
+
+  sources = [
+    "file_testing.dart",
+    "src/testing/core_matchers.dart",
+    "src/testing/internal.dart",
+  ]
+}
diff --git a/file_testing/CHANGELOG.md b/file_testing/CHANGELOG.md
new file mode 100644
index 0000000..ee6e2be
--- /dev/null
+++ b/file_testing/CHANGELOG.md
@@ -0,0 +1,27 @@
+#### 2.1.0
+
+* Changed dependency on `package:test` to `package:test_api`
+* Bumped Dart SDK constraint to match `package:test_api`'s requirements
+* Updated style to match latest lint rules from Flutter repo.
+
+#### 2.0.3
+
+* Relaxed constraints on `package:test`
+
+#### 2.0.2
+
+* Bumped dependency on `package:test` to version 1.0
+
+#### 2.0.1
+
+* Bumped Dart SDK constraint to allow for Dart 2 stable
+
+#### 2.0.0
+
+* Removed `record_replay_matchers.dart` from API
+
+#### 1.0.0
+
+* Moved `package:file/testing.dart` library into a dedicated package so that
+  libraries don't need to take on a transitive dependency on `package:test`
+  in order to use `package:file`.
diff --git a/file_testing/LICENSE b/file_testing/LICENSE
new file mode 100644
index 0000000..076334f
--- /dev/null
+++ b/file_testing/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2017, 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:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/file_testing/README.md b/file_testing/README.md
new file mode 100644
index 0000000..ca6c652
--- /dev/null
+++ b/file_testing/README.md
@@ -0,0 +1,32 @@
+# file_testing
+
+Testing utilities intended to work with `package:file`
+
+## Features
+
+This package provides a series of matchers to be used in tests that work with file
+system types.
+
+## Usage
+
+```dart
+import 'package:file/file.dart';
+import 'package:file_testing/file_testing.dart';
+import 'package:test/test.dart';
+
+test('some test', () {
+  MemoryFileSystem fs;
+
+  setUp(() {
+    fs = new MemoryFileSystem();
+    fs.file('/foo').createSync();
+  });
+
+  expectFileSystemException(ErrorCodes.ENOENT, () {
+    fs.directory('').resolveSymbolicLinksSync();
+  });
+  expect(fs.file('/path/to/file'), isFile);
+  expect(fs.file('/path/to/directory'), isDirectory);
+  expect(fs.file('/foo'), exists);
+});
+```
diff --git a/file_testing/lib/file_testing.dart b/file_testing/lib/file_testing.dart
new file mode 100644
index 0000000..35fcdac
--- /dev/null
+++ b/file_testing/lib/file_testing.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2017, 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.
+
+/// Matchers (from `package:test`) for use in tests that deal with file systems.
+export 'src/testing/core_matchers.dart';
diff --git a/file_testing/lib/src/testing/core_matchers.dart b/file_testing/lib/src/testing/core_matchers.dart
new file mode 100644
index 0000000..adce554
--- /dev/null
+++ b/file_testing/lib/src/testing/core_matchers.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2017, 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:test_api/test_api.dart';
+
+import 'internal.dart';
+
+/// Matcher that successfully matches against any instance of [Directory].
+const Matcher isDirectory = TypeMatcher<Directory>();
+
+/// Matcher that successfully matches against any instance of [File].
+const Matcher isFile = TypeMatcher<File>();
+
+/// Matcher that successfully matches against any instance of [Link].
+const Matcher isLink = TypeMatcher<Link>();
+
+/// Matcher that successfully matches against any instance of
+/// [FileSystemEntity].
+const Matcher isFileSystemEntity = TypeMatcher<FileSystemEntity>();
+
+/// Matcher that successfully matches against any instance of [FileStat].
+const Matcher isFileStat = TypeMatcher<FileStat>();
+
+/// Returns a [Matcher] that matches [path] against an entity's path.
+///
+/// [path] may be a String, a predicate function, or a [Matcher]. If it is
+/// a String, it will be wrapped in an equality matcher.
+Matcher hasPath(dynamic path) => _HasPath(path);
+
+/// Returns a [Matcher] that successfully matches against an instance of
+/// [FileSystemException].
+///
+/// If [osErrorCode] is specified, matches will be limited to exceptions whose
+/// `osError.errorCode` also match the specified matcher.
+///
+/// [osErrorCode] may be an `int`, a predicate function, or a [Matcher]. If it
+/// is an `int`, it will be wrapped in an equality matcher.
+Matcher isFileSystemException([dynamic osErrorCode]) =>
+    _FileSystemException(osErrorCode);
+
+/// Returns a matcher that successfully matches against a future or function
+/// that throws a [FileSystemException].
+///
+/// If [osErrorCode] is specified, matches will be limited to exceptions whose
+/// `osError.errorCode` also match the specified matcher.
+///
+/// [osErrorCode] may be an `int`, a predicate function, or a [Matcher]. If it
+/// is an `int`, it will be wrapped in an equality matcher.
+Matcher throwsFileSystemException([dynamic osErrorCode]) =>
+    throwsA(isFileSystemException(osErrorCode));
+
+/// Expects the specified [callback] to throw a [FileSystemException] with the
+/// specified [osErrorCode] (matched against the exception's
+/// `osError.errorCode`).
+///
+/// [osErrorCode] may be an `int`, a predicate function, or a [Matcher]. If it
+/// is an `int`, it will be wrapped in an equality matcher.
+///
+/// See also:
+///   - [ErrorCodes]
+void expectFileSystemException(dynamic osErrorCode, void callback()) {
+  expect(callback, throwsFileSystemException(osErrorCode));
+}
+
+/// Matcher that successfully matches against a [FileSystemEntity] that
+/// exists ([FileSystemEntity.existsSync] returns true).
+const Matcher exists = _Exists();
+
+class _FileSystemException extends Matcher {
+  _FileSystemException(dynamic osErrorCode)
+      : _matcher = _wrapMatcher(osErrorCode);
+
+  final Matcher _matcher;
+
+  static Matcher _wrapMatcher(dynamic osErrorCode) {
+    if (osErrorCode == null) {
+      return null;
+    }
+    return ignoreOsErrorCodes ? anything : wrapMatcher(osErrorCode);
+  }
+
+  @override
+  bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
+    if (item is FileSystemException) {
+      return _matcher == null ||
+          _matcher.matches(item.osError?.errorCode, matchState);
+    }
+    return false;
+  }
+
+  @override
+  Description describe(Description desc) {
+    if (_matcher == null) {
+      return desc.add('FileSystemException');
+    } else {
+      desc.add('FileSystemException with osError.errorCode: ');
+      return _matcher.describe(desc);
+    }
+  }
+}
+
+class _HasPath extends Matcher {
+  _HasPath(dynamic path) : _matcher = wrapMatcher(path);
+
+  final Matcher _matcher;
+
+  @override
+  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
+      _matcher.matches(item.path, matchState);
+
+  @override
+  Description describe(Description desc) {
+    desc.add('has path: ');
+    return _matcher.describe(desc);
+  }
+
+  @override
+  Description describeMismatch(
+    dynamic item,
+    Description desc,
+    Map<dynamic, dynamic> matchState,
+    bool verbose,
+  ) {
+    desc.add('has path: \'${item.path}\'').add('\n   Which: ');
+    final Description pathDesc = StringDescription();
+    _matcher.describeMismatch(item.path, pathDesc, matchState, verbose);
+    desc.add(pathDesc.toString());
+    return desc;
+  }
+}
+
+class _Exists extends Matcher {
+  const _Exists();
+
+  @override
+  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
+      item is FileSystemEntity && item.existsSync();
+
+  @override
+  Description describe(Description description) =>
+      description.add('a file system entity that exists');
+
+  @override
+  Description describeMismatch(
+    dynamic item,
+    Description description,
+    Map<dynamic, dynamic> matchState,
+    bool verbose,
+  ) {
+    return description.add('does not exist');
+  }
+}
diff --git a/file_testing/lib/src/testing/internal.dart b/file_testing/lib/src/testing/internal.dart
new file mode 100644
index 0000000..d0cf002
--- /dev/null
+++ b/file_testing/lib/src/testing/internal.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, 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:meta/meta.dart';
+
+/// True if we should ignore OS error codes in our matchers.
+@visibleForTesting
+bool ignoreOsErrorCodes = false;
diff --git a/file_testing/pubspec.yaml b/file_testing/pubspec.yaml
new file mode 100644
index 0000000..8da2eb7
--- /dev/null
+++ b/file_testing/pubspec.yaml
@@ -0,0 +1,13 @@
+name: file_testing
+version: 2.1.0
+authors:
+- Todd Volkert <tvolkert@google.com>
+description: Testing utilities for package:file
+homepage: https://github.com/google/file.dart/packages/file_testing
+
+dependencies:
+  meta: ^1.1.2
+  test_api: ^0.2.2
+
+environment:
+  sdk: '>=2.1.0 <3.0.0'
diff --git a/html/.travis.yml b/html/.travis.yml
index 3f5bcfb..0033332 100644
--- a/html/.travis.yml
+++ b/html/.travis.yml
@@ -7,17 +7,12 @@
 dart_task:
   - test: -p vm
   - test: -p chrome
+  - dartanalyzer: --fatal-warnings --fatal-infos .
 
 matrix:
   include:
     - dart: dev
       dart_task: dartfmt
-    - dart: dev
-      dart_task:
-        dartanalyzer: --fatal-warnings --fatal-infos .
-    - dart: 2.3.0
-      dart_task:
-        dartanalyzer: --fatal-warnings .
 
 # Only building master means that we don't run two builds for each pull request.
 branches:
diff --git a/html/BUILD.gn b/html/BUILD.gn
index 26da133..68404a7 100644
--- a/html/BUILD.gn
+++ b/html/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for html-0.14.0+4
+# This file is generated by importer.py for html-0.14.0+3
 
 import("//build/dart/dart_library.gni")
 
diff --git a/html/CHANGELOG.md b/html/CHANGELOG.md
index 53d7970..21fc041 100644
--- a/html/CHANGELOG.md
+++ b/html/CHANGELOG.md
@@ -1,8 +1,3 @@
-## 0.14.0+4
-
-- Fix a bug parsing bad HTML where a 'button' end tag needs to close other
-  elements.
-
 ## 0.14.0+3
 
 - Fix spans generated for HTML with higher-plane unicode characters
diff --git a/html/analysis_options.yaml b/html/analysis_options.yaml
index b8dcf93..2d3a54d 100644
--- a/html/analysis_options.yaml
+++ b/html/analysis_options.yaml
@@ -1,8 +1,6 @@
 include: package:pedantic/analysis_options.yaml
 analyzer:
   errors:
-    # https://github.com/dart-lang/linter/issues/1649
-    prefer_collection_literals: ignore
     unused_element: error
     unused_import: error
     unused_local_variable: error
diff --git a/html/lib/dom.dart b/html/lib/dom.dart
index 835d8da..08d1c12 100644
--- a/html/lib/dom.dart
+++ b/html/lib/dom.dart
@@ -36,7 +36,6 @@
 
   const AttributeName(this.prefix, this.name, this.namespace);
 
-  @override
   String toString() {
     // Implement:
     // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
@@ -46,26 +45,24 @@
     return prefix != null ? '$prefix:$name' : name;
   }
 
-  @override
   int get hashCode {
-    var h = prefix.hashCode;
+    int h = prefix.hashCode;
     h = 37 * (h & 0x1FFFFF) + name.hashCode;
     h = 37 * (h & 0x1FFFFF) + namespace.hashCode;
     return h & 0x3FFFFFFF;
   }
 
-  @override
   int compareTo(other) {
     // Not sure about this sort order
     if (other is! AttributeName) return 1;
-    var cmp = (prefix ?? '').compareTo((other.prefix ?? ''));
+    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);
   }
 
-  @override
   bool operator ==(x) {
     if (x is! AttributeName) return false;
     return prefix == x.prefix && name == x.name && namespace == x.namespace;
@@ -187,7 +184,12 @@
     return _attributeValueSpans;
   }
 
-  List<Element> get children => _elements ??= FilteredElementList(this);
+  List<Element> get children {
+    if (_elements == null) {
+      _elements = FilteredElementList(this);
+    }
+    return _elements;
+  }
 
   /// Returns a copy of this node.
   ///
@@ -221,7 +223,7 @@
   void _addOuterHtml(StringBuffer str);
 
   void _addInnerHtml(StringBuffer str) {
-    for (var child in nodes) {
+    for (Node child in nodes) {
       child._addOuterHtml(str);
     }
   }
@@ -299,7 +301,7 @@
     }
   }
 
-  Node _clone(Node shallowClone, bool deep) {
+  _clone(Node shallowClone, bool deep) {
     if (deep) {
       for (var child in nodes) {
         shallowClone.append(child.clone(true));
@@ -314,7 +316,6 @@
   Document() : super._();
   factory Document.html(String html) => parse(html);
 
-  @override
   int get nodeType => Node.DOCUMENT_NODE;
 
   // TODO(jmesserly): optmize this if needed
@@ -330,13 +331,10 @@
   // to dom_parsing, where we keep other custom APIs?
   String get outerHtml => _outerHtml;
 
-  @override
-  String toString() => '#document';
+  String toString() => "#document";
 
-  @override
   void _addOuterHtml(StringBuffer str) => _addInnerHtml(str);
 
-  @override
   Document clone(bool deep) => _clone(Document(), deep);
 
   Element createElement(String tag) => Element.tag(tag);
@@ -355,7 +353,6 @@
   DocumentFragment() : super._();
   factory DocumentFragment.html(String html) => parseFragment(html);
 
-  @override
   int get nodeType => Node.DOCUMENT_FRAGMENT_NODE;
 
   /// Returns a fragment of HTML or XML that represents the element and its
@@ -366,18 +363,13 @@
   // to dom_parsing, where we keep other custom APIs?
   String get outerHtml => _outerHtml;
 
-  @override
-  String toString() => '#document-fragment';
+  String toString() => "#document-fragment";
 
-  @override
   DocumentFragment clone(bool deep) => _clone(DocumentFragment(), deep);
 
-  @override
   void _addOuterHtml(StringBuffer str) => _addInnerHtml(str);
 
-  @override
   String get text => _getText(this);
-  @override
   set text(String value) => _setText(this, value);
 }
 
@@ -388,28 +380,24 @@
 
   DocumentType(this.name, this.publicId, this.systemId) : super._();
 
-  @override
   int get nodeType => Node.DOCUMENT_TYPE_NODE;
 
-  @override
   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 ?? '';
-      var sid = systemId ?? '';
+      var pid = publicId != null ? publicId : '';
+      var sid = systemId != null ? systemId : '';
       return '<!DOCTYPE $name "$pid" "$sid">';
     } else {
       return '<!DOCTYPE $name>';
     }
   }
 
-  @override
   void _addOuterHtml(StringBuffer str) {
     str.write(toString());
   }
 
-  @override
   DocumentType clone(bool deep) => DocumentType(name, publicId, systemId);
 }
 
@@ -420,24 +408,20 @@
   dynamic _data;
 
   Text(String data)
-      : _data = data ?? '',
+      : _data = data != null ? data : '',
         super._();
 
-  @override
   int get nodeType => Node.TEXT_NODE;
 
   String get data => _data = _data.toString();
   set data(String value) {
-    _data = value ?? '';
+    _data = value != null ? value : '';
   }
 
-  @override
   String toString() => '"$data"';
 
-  @override
   void _addOuterHtml(StringBuffer str) => writeTextNodeAsHtml(str, this);
 
-  @override
   Text clone(bool deep) => Text(data);
 
   void appendData(String data) {
@@ -446,9 +430,7 @@
     sb.write(data);
   }
 
-  @override
   String get text => data;
-  @override
   set text(String value) {
     data = value;
   }
@@ -502,7 +484,7 @@
     // 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.
-    var parentTag = 'div';
+    String parentTag = 'div';
     String tag;
     final match = _startTagRegexp.firstMatch(html);
     if (match != null) {
@@ -527,14 +509,13 @@
     return element;
   }
 
-  @override
   int get nodeType => Node.ELEMENT_NODE;
 
   // TODO(jmesserly): we can make this faster
   Element get previousElementSibling {
     if (parentNode == null) return null;
     var siblings = parentNode.nodes;
-    for (var i = siblings.indexOf(this) - 1; i >= 0; i--) {
+    for (int i = siblings.indexOf(this) - 1; i >= 0; i--) {
       var s = siblings[i];
       if (s is Element) return s;
     }
@@ -544,22 +525,19 @@
   Element get nextElementSibling {
     if (parentNode == null) return null;
     var siblings = parentNode.nodes;
-    for (var i = siblings.indexOf(this) + 1; i < siblings.length; i++) {
+    for (int i = siblings.indexOf(this) + 1; i < siblings.length; i++) {
       var s = siblings[i];
       if (s is Element) return s;
     }
     return null;
   }
 
-  @override
   String toString() {
     var prefix = Namespaces.getPrefix(namespaceUri);
     return "<${prefix == null ? '' : '$prefix '}$localName>";
   }
 
-  @override
   String get text => _getText(this);
-  @override
   set text(String value) => _setText(this, value);
 
   /// Returns a fragment of HTML or XML that represents the element and its
@@ -579,7 +557,6 @@
     nodes.addAll(parseFragment(value, container: localName).nodes);
   }
 
-  @override
   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.
@@ -634,7 +611,6 @@
     return prefix == null ? '' : '$prefix:';
   }
 
-  @override
   Element clone(bool deep) {
     var result = Element._(localName, namespaceUri)
       ..attributes = LinkedHashMap.from(attributes);
@@ -644,7 +620,7 @@
   // http://dom.spec.whatwg.org/#dom-element-id
   String get id {
     var result = attributes['id'];
-    return result ?? '';
+    return result != null ? result : '';
   }
 
   set id(String value) {
@@ -654,7 +630,7 @@
   // http://dom.spec.whatwg.org/#dom-element-classname
   String get className {
     var result = attributes['class'];
-    return result ?? '';
+    return result != null ? result : '';
   }
 
   set className(String value) {
@@ -677,23 +653,17 @@
 
   Comment(this.data) : super._();
 
-  @override
   int get nodeType => Node.COMMENT_NODE;
 
-  @override
-  String toString() => '<!-- $data -->';
+  String toString() => "<!-- $data -->";
 
-  @override
   void _addOuterHtml(StringBuffer str) {
-    str.write('<!--$data-->');
+    str.write("<!--$data-->");
   }
 
-  @override
   Comment clone(bool deep) => Comment(data);
 
-  @override
   String get text => data;
-  @override
   set text(String value) {
     data = value;
   }
@@ -717,7 +687,6 @@
     return node;
   }
 
-  @override
   void add(Node value) {
     if (value is DocumentFragment) {
       addAll(value.nodes);
@@ -728,7 +697,6 @@
 
   void addLast(Node value) => add(value);
 
-  @override
   void addAll(Iterable<Node> collection) {
     // Note: we need to be careful if collection is another NodeList.
     // In particular:
@@ -744,7 +712,6 @@
     super.addAll(list);
   }
 
-  @override
   void insert(int index, Node value) {
     if (value is DocumentFragment) {
       insertAll(index, value.nodes);
@@ -753,13 +720,10 @@
     }
   }
 
-  @override
   Node removeLast() => super.removeLast()..parentNode = null;
 
-  @override
   Node removeAt(int i) => super.removeAt(i)..parentNode = null;
 
-  @override
   void clear() {
     for (var node in this) {
       node.parentNode = null;
@@ -767,7 +731,6 @@
     super.clear();
   }
 
-  @override
   void operator []=(int index, Node value) {
     if (value is DocumentFragment) {
       removeAt(index);
@@ -780,52 +743,46 @@
 
   // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see
   // http://code.google.com/p/dart/issues/detail?id=5371
-  @override
   void setRange(int start, int rangeLength, Iterable<Node> from,
       [int startFrom = 0]) {
-    var fromVar = from as List<Node>;
+    List<Node> fromVar = from as List<Node>;
     if (fromVar is NodeList) {
       // Note: this is presumed to make a copy
       fromVar = fromVar.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 (var i = rangeLength - 1; i >= 0; i--) {
+    for (int i = rangeLength - 1; i >= 0; i--) {
       this[start + i] = fromVar[startFrom + i];
     }
   }
 
-  @override
   void replaceRange(int start, int end, Iterable<Node> newContents) {
     removeRange(start, end);
     insertAll(start, newContents);
   }
 
-  @override
   void removeRange(int start, int rangeLength) {
-    for (var i = start; i < rangeLength; i++) {
+    for (int i = start; i < rangeLength; i++) {
       this[i].parentNode = null;
     }
     super.removeRange(start, rangeLength);
   }
 
-  @override
-  void removeWhere(bool Function(Node) test) {
+  void removeWhere(bool test(Node e)) {
     for (var node in where(test)) {
       node.parentNode = null;
     }
     super.removeWhere(test);
   }
 
-  @override
-  void retainWhere(bool Function(Node) test) {
+  void retainWhere(bool test(Node e)) {
     for (var node in where((n) => !test(n))) {
       node.parentNode = null;
     }
     super.retainWhere(test);
   }
 
-  @override
   void insertAll(int index, Iterable<Node> collection) {
     // Note: we need to be careful how we copy nodes. See note in addAll.
     var list = _flattenDocFragments(collection);
@@ -875,85 +832,70 @@
   // forEach, every, any, ... could directly work on the _childNodes.
   List<Element> get _filtered => _childNodes.whereType<Element>().toList();
 
-  @override
-  void forEach(void Function(Element) f) {
+  void forEach(void f(Element element)) {
     _filtered.forEach(f);
   }
 
-  @override
   void operator []=(int index, Element value) {
     this[index].replaceWith(value);
   }
 
-  @override
   set length(int newLength) {
     final len = length;
     if (newLength >= len) {
       return;
     } else if (newLength < 0) {
-      throw ArgumentError('Invalid list length');
+      throw ArgumentError("Invalid list length");
     }
 
     removeRange(newLength, len);
   }
 
-  @override
-  String join([String separator = '']) => _filtered.join(separator);
+  String join([String separator = ""]) => _filtered.join(separator);
 
-  @override
   void add(Element value) {
     _childNodes.add(value);
   }
 
-  @override
   void addAll(Iterable<Element> iterable) {
-    for (var element in iterable) {
+    for (Element element in iterable) {
       add(element);
     }
   }
 
-  @override
   bool contains(Object element) {
     return element is Element && _childNodes.contains(element);
   }
 
-  @override
   Iterable<Element> get reversed => _filtered.reversed;
 
-  @override
-  void sort([int Function(Element, Element) compare]) {
+  void sort([int compare(Element a, Element b)]) {
     throw UnsupportedError('TODO(jacobr): should we impl?');
   }
 
-  @override
   void setRange(int start, int end, Iterable<Element> iterable,
       [int skipCount = 0]) {
     throw UnimplementedError();
   }
 
-  @override
   void fillRange(int start, int end, [Element fillValue]) {
     throw UnimplementedError();
   }
 
-  @override
   void replaceRange(int start, int end, Iterable<Element> iterable) {
     throw UnimplementedError();
   }
 
-  @override
   void removeRange(int start, int end) {
     _filtered.sublist(start, end).forEach((el) => el.remove());
   }
 
-  @override
   void clear() {
     // Currently, ElementList#clear clears even non-element nodes, so we follow
     // that behavior.
     _childNodes.clear();
   }
 
-  @override
   Element removeLast() {
     final result = last;
     if (result != null) {
@@ -962,35 +904,28 @@
     return result;
   }
 
-  @override
-  Iterable<T> map<T>(T Function(Element) f) => _filtered.map(f);
-  @override
-  Iterable<Element> where(bool Function(Element) f) => _filtered.where(f);
-  @override
-  Iterable<T> expand<T>(Iterable<T> Function(Element) f) => _filtered.expand(f);
+  Iterable<T> map<T>(T f(Element element)) => _filtered.map(f);
+  Iterable<Element> where(bool f(Element element)) => _filtered.where(f);
+  Iterable<T> expand<T>(Iterable<T> f(Element element)) => _filtered.expand(f);
 
-  @override
   void insert(int index, Element value) {
     _childNodes.insert(index, value);
   }
 
-  @override
   void insertAll(int index, Iterable<Element> iterable) {
     _childNodes.insertAll(index, iterable);
   }
 
-  @override
   Element removeAt(int index) {
     final result = this[index];
     result.remove();
     return result;
   }
 
-  @override
   bool remove(Object element) {
     if (element is! Element) return false;
-    for (var i = 0; i < length; i++) {
-      var indexElement = this[i];
+    for (int i = 0; i < length; i++) {
+      Element indexElement = this[i];
       if (identical(indexElement, element)) {
         indexElement.remove();
         return true;
@@ -999,82 +934,59 @@
     return false;
   }
 
-  @override
-  Element reduce(Element Function(Element, Element) combine) {
+  Element reduce(Element combine(Element value, Element element)) {
     return _filtered.reduce(combine);
   }
 
-  @override
-  T fold<T>(
-      T initialValue, T Function(T previousValue, Element element) combine) {
+  T fold<T>(T initialValue, T combine(T previousValue, Element element)) {
     return _filtered.fold(initialValue, combine);
   }
 
-  @override
-  bool every(bool Function(Element) f) => _filtered.every(f);
-  @override
-  bool any(bool Function(Element) f) => _filtered.any(f);
-  @override
+  bool every(bool f(Element element)) => _filtered.every(f);
+  bool any(bool f(Element element)) => _filtered.any(f);
   List<Element> toList({bool growable = true}) =>
       List<Element>.from(this, growable: growable);
-  @override
   Set<Element> toSet() => Set<Element>.from(this);
-  @override
-  Element firstWhere(bool Function(Element) test, {Element Function() orElse}) {
+  Element firstWhere(bool test(Element value), {Element orElse()}) {
     return _filtered.firstWhere(test, orElse: orElse);
   }
 
-  @override
-  Element lastWhere(bool Function(Element) test, {Element Function() orElse}) {
+  Element lastWhere(bool test(Element value), {Element orElse()}) {
     return _filtered.lastWhere(test, orElse: orElse);
   }
 
-  @override
-  Element singleWhere(bool Function(Element) test,
-      {Element Function() orElse}) {
+  Element singleWhere(bool test(Element value), {Element orElse()}) {
     if (orElse != null) throw UnimplementedError('orElse');
     return _filtered.singleWhere(test);
   }
 
-  @override
   Element elementAt(int index) {
     return this[index];
   }
 
-  @override
   bool get isEmpty => _filtered.isEmpty;
-  @override
   int get length => _filtered.length;
-  @override
   Element operator [](int index) => _filtered[index];
-  @override
   Iterator<Element> get iterator => _filtered.iterator;
-  @override
   List<Element> sublist(int start, [int end]) => _filtered.sublist(start, end);
-  @override
   Iterable<Element> getRange(int start, int end) =>
       _filtered.getRange(start, end);
   // TODO(sigmund): this should be typed Element, but we currently run into a
   // bug where ListMixin<E>.indexOf() expects Object as the argument.
-  @override
   int indexOf(Object element, [int start = 0]) =>
       _filtered.indexOf(element, start);
 
   // TODO(sigmund): this should be typed Element, but we currently run into a
   // bug where ListMixin<E>.lastIndexOf() expects Object as the argument.
-  @override
   int lastIndexOf(Object element, [int start]) {
-    start ??= length - 1;
+    if (start == null) start = length - 1;
     return _filtered.lastIndexOf(element, start);
   }
 
-  @override
   Element get first => _filtered.first;
 
-  @override
   Element get last => _filtered.last;
 
-  @override
   Element get single => _filtered.single;
 }
 
@@ -1090,11 +1002,9 @@
 class _ConcatTextVisitor extends TreeVisitor {
   final _str = StringBuffer();
 
-  @override
   String toString() => _str.toString();
 
-  @override
-  void visitText(Text node) {
+  visitText(Text node) {
     _str.write(node.data);
   }
 }
diff --git a/html/lib/dom_parsing.dart b/html/lib/dom_parsing.dart
index f16018c..27eedb3 100644
--- a/html/lib/dom_parsing.dart
+++ b/html/lib/dom_parsing.dart
@@ -7,7 +7,7 @@
 
 /// A simple tree visitor for the DOM nodes.
 class TreeVisitor {
-  void visit(Node node) {
+  visit(Node node) {
     switch (node.nodeType) {
       case Node.ELEMENT_NODE:
         return visitElement(node);
@@ -26,7 +26,7 @@
     }
   }
 
-  void visitChildren(Node node) {
+  visitChildren(Node node) {
     // Allow for mutations (remove works) while iterating.
     for (var child in node.nodes.toList()) {
       visit(child);
@@ -36,20 +36,20 @@
   /// 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.
-  void visitNodeFallback(Node node) => visitChildren(node);
+  visitNodeFallback(Node node) => visitChildren(node);
 
-  void visitDocument(Document node) => visitNodeFallback(node);
+  visitDocument(Document node) => visitNodeFallback(node);
 
-  void visitDocumentType(DocumentType node) => visitNodeFallback(node);
+  visitDocumentType(DocumentType node) => visitNodeFallback(node);
 
-  void visitText(Text node) => visitNodeFallback(node);
+  visitText(Text node) => visitNodeFallback(node);
 
   // TODO(jmesserly): visit attributes.
-  void visitElement(Element node) => visitNodeFallback(node);
+  visitElement(Element node) => visitNodeFallback(node);
 
-  void visitComment(Comment node) => visitNodeFallback(node);
+  visitComment(Comment node) => visitNodeFallback(node);
 
-  void visitDocumentFragment(DocumentFragment node) => visitNodeFallback(node);
+  visitDocumentFragment(DocumentFragment node) => visitNodeFallback(node);
 }
 
 /// Converts the DOM tree into an HTML string with code markup suitable for
@@ -67,29 +67,24 @@
 
   CodeMarkupVisitor() : _str = StringBuffer();
 
-  @override
   String toString() => _str.toString();
 
-  @override
-  void visitDocument(Document node) {
-    _str.write('<pre>');
+  visitDocument(Document node) {
+    _str.write("<pre>");
     visitChildren(node);
-    _str.write('</pre>');
+    _str.write("</pre>");
   }
 
-  @override
-  void visitDocumentType(DocumentType node) {
+  visitDocumentType(DocumentType node) {
     _str.write('<code class="markup doctype">&lt;!DOCTYPE ${node.name}>'
         '</code>');
   }
 
-  @override
-  void visitText(Text node) {
+  visitText(Text node) {
     writeTextNodeAsHtml(_str, node);
   }
 
-  @override
-  void visitElement(Element node) {
+  visitElement(Element node) {
     final tag = node.localName;
     _str.write('&lt;<code class="markup element-name">$tag</code>');
     if (node.attributes.isNotEmpty) {
@@ -100,17 +95,16 @@
       });
     }
     if (node.nodes.isNotEmpty) {
-      _str.write('>');
+      _str.write(">");
       visitChildren(node);
     } else if (isVoidElement(tag)) {
-      _str.write('>');
+      _str.write(">");
       return;
     }
     _str.write('&lt;/<code class="markup element-name">$tag</code>>');
   }
 
-  @override
-  void visitComment(Comment node) {
+  visitComment(Comment node) {
     var data = htmlSerializeEscape(node.data);
     _str.write('<code class="markup comment">&lt;!--$data--></code>');
   }
@@ -137,7 +131,7 @@
   // TODO(jmesserly): is it faster to build up a list of codepoints?
   // StringBuffer seems cleaner assuming Dart can unbox 1-char strings.
   StringBuffer result;
-  for (var i = 0; i < text.length; i++) {
+  for (int i = 0; i < text.length; i++) {
     var ch = text[i];
     String replace;
     switch (ch) {
@@ -158,7 +152,7 @@
         break;
     }
     if (replace != null) {
-      result ??= StringBuffer(text.substring(0, i));
+      if (result == null) result = StringBuffer(text.substring(0, i));
       result.write(replace);
     } else if (result != null) {
       result.write(ch);
@@ -174,22 +168,22 @@
 /// See also: <http://dev.w3.org/html5/markup/syntax.html#void-elements>.
 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':
+    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/html/lib/parser.dart b/html/lib/parser.dart
index 46702ae..58ae1c8 100644
--- a/html/lib/parser.dart
+++ b/html/lib/parser.dart
@@ -56,7 +56,7 @@
 /// additionally pass [sourceUrl] to indicate where the [input] was extracted
 /// from.
 DocumentFragment parseFragment(input,
-    {String container = 'div',
+    {String container = "div",
     String encoding,
     bool generateSpans = false,
     String sourceUrl}) {
@@ -86,7 +86,7 @@
 
   // TODO(jmesserly): use enum?
   /// "quirks" / "limited quirks" / "no quirks"
-  String compatMode = 'no quirks';
+  String compatMode = "no quirks";
 
   /// innerHTML container when parsing document fragment.
   String innerHTML;
@@ -150,7 +150,7 @@
       this.generateSpans = false,
       String sourceUrl,
       TreeBuilder tree})
-      : tree = tree ?? TreeBuilder(true),
+      : tree = tree != null ? tree : TreeBuilder(true),
         tokenizer = (input is HtmlTokenizer
             ? input
             : HtmlTokenizer(input,
@@ -203,7 +203,7 @@
   /// 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']) {
+  DocumentFragment parseFragment([String container = "div"]) {
     if (container == null) throw ArgumentError('container');
     innerHTML = container.toLowerCase();
     _parse();
@@ -232,7 +232,7 @@
     firstStartTag = false;
     errors.clear();
     // "quirks" / "limited quirks" / "no quirks"
-    compatMode = 'no quirks';
+    compatMode = "no quirks";
 
     if (innerHTMLMode) {
       if (cdataElements.contains(innerHTML)) {
@@ -258,11 +258,11 @@
   }
 
   bool isHTMLIntegrationPoint(Element element) {
-    if (element.localName == 'annotation-xml' &&
+    if (element.localName == "annotation-xml" &&
         element.namespaceUri == Namespaces.mathml) {
-      var enc = element.attributes['encoding'];
+      var enc = element.attributes["encoding"];
       if (enc != null) enc = asciiUpper2Lower(enc);
-      return enc == 'text/html' || enc == 'application/xhtml+xml';
+      return enc == "text/html" || enc == "application/xhtml+xml";
     } else {
       return htmlIntegrationPointElements
           .contains(Pair(element.namespaceUri, element.localName));
@@ -282,8 +282,8 @@
 
     if (isMathMLTextIntegrationPoint(node)) {
       if (type == TokenKind.startTag &&
-          (token as StartTagToken).name != 'mglyph' &&
-          (token as StartTagToken).name != 'malignmark') {
+          (token as StartTagToken).name != "mglyph" &&
+          (token as StartTagToken).name != "malignmark") {
         return false;
       }
       if (type == TokenKind.characters || type == TokenKind.spaceCharacters) {
@@ -291,9 +291,9 @@
       }
     }
 
-    if (node.localName == 'annotation-xml' &&
+    if (node.localName == "annotation-xml" &&
         type == TokenKind.startTag &&
-        (token as StartTagToken).name == 'svg') {
+        (token as StartTagToken).name == "svg") {
       return false;
     }
 
@@ -322,7 +322,7 @@
           parseError(error.span, error.data, error.messageParams);
           newToken = null;
         } else {
-          var localPhase = phase;
+          Phase localPhase = phase;
           if (inForeignContent(token, type)) {
             localPhase = _inForeignContentPhase;
           }
@@ -352,8 +352,8 @@
 
       if (token is StartTagToken) {
         if (token.selfClosing && !token.selfClosingAcknowledged) {
-          parseError(token.span, 'non-void-element-with-trailing-solidus',
-              {'name': token.name});
+          parseError(token.span, "non-void-element-with-trailing-solidus",
+              {"name": token.name});
         }
       }
     }
@@ -390,76 +390,76 @@
   }
 
   void adjustMathMLAttributes(StartTagToken token) {
-    var orig = token.data.remove('definitionurl');
+    var orig = token.data.remove("definitionurl");
     if (orig != null) {
-      token.data['definitionURL'] = orig;
+      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'
+      "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];
@@ -473,18 +473,18 @@
     // 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': AttributeName('xlink', 'actuate', Namespaces.xlink),
-      'xlink:arcrole': AttributeName('xlink', 'arcrole', Namespaces.xlink),
-      'xlink:href': AttributeName('xlink', 'href', Namespaces.xlink),
-      'xlink:role': AttributeName('xlink', 'role', Namespaces.xlink),
-      'xlink:show': AttributeName('xlink', 'show', Namespaces.xlink),
-      'xlink:title': AttributeName('xlink', 'title', Namespaces.xlink),
-      'xlink:type': AttributeName('xlink', 'type', Namespaces.xlink),
-      'xml:base': AttributeName('xml', 'base', Namespaces.xml),
-      'xml:lang': AttributeName('xml', 'lang', Namespaces.xml),
-      'xml:space': AttributeName('xml', 'space', Namespaces.xml),
-      'xmlns': AttributeName(null, 'xmlns', Namespaces.xmlns),
-      'xmlns:xlink': AttributeName('xmlns', 'xlink', Namespaces.xmlns)
+      "xlink:actuate": AttributeName("xlink", "actuate", Namespaces.xlink),
+      "xlink:arcrole": AttributeName("xlink", "arcrole", Namespaces.xlink),
+      "xlink:href": AttributeName("xlink", "href", Namespaces.xlink),
+      "xlink:role": AttributeName("xlink", "role", Namespaces.xlink),
+      "xlink:show": AttributeName("xlink", "show", Namespaces.xlink),
+      "xlink:title": AttributeName("xlink", "title", Namespaces.xlink),
+      "xlink:type": AttributeName("xlink", "type", Namespaces.xlink),
+      "xml:base": AttributeName("xml", "base", Namespaces.xml),
+      "xml:lang": AttributeName("xml", "lang", Namespaces.xml),
+      "xml:space": AttributeName("xml", "space", Namespaces.xml),
+      "xmlns": AttributeName(null, "xmlns", Namespaces.xmlns),
+      "xmlns:xlink": AttributeName("xmlns", "xlink", Namespaces.xmlns)
     };
 
     for (var originalName in token.data.keys.toList()) {
@@ -500,7 +500,7 @@
     // specification.)
     for (var node in tree.openElements.reversed) {
       var nodeName = node.localName;
-      var last = node == tree.openElements[0];
+      bool last = node == tree.openElements[0];
       if (last) {
         assert(innerHTMLMode);
         nodeName = innerHTML;
@@ -508,10 +508,10 @@
       // Check for conditions that should only happen in the innerHTML
       // case
       switch (nodeName) {
-        case 'select':
-        case 'colgroup':
-        case 'head':
-        case 'html':
+        case "select":
+        case "colgroup":
+        case "head":
+        case "html":
           assert(innerHTMLMode);
           break;
       }
@@ -519,46 +519,46 @@
         continue;
       }
       switch (nodeName) {
-        case 'select':
+        case "select":
           phase = _inSelectPhase;
           return;
-        case 'td':
+        case "td":
           phase = _inCellPhase;
           return;
-        case 'th':
+        case "th":
           phase = _inCellPhase;
           return;
-        case 'tr':
+        case "tr":
           phase = _inRowPhase;
           return;
-        case 'tbody':
+        case "tbody":
           phase = _inTableBodyPhase;
           return;
-        case 'thead':
+        case "thead":
           phase = _inTableBodyPhase;
           return;
-        case 'tfoot':
+        case "tfoot":
           phase = _inTableBodyPhase;
           return;
-        case 'caption':
+        case "caption":
           phase = _inCaptionPhase;
           return;
-        case 'colgroup':
+        case "colgroup":
           phase = _inColumnGroupPhase;
           return;
-        case 'table':
+        case "table":
           phase = _inTablePhase;
           return;
-        case 'head':
+        case "head":
           phase = _inBodyPhase;
           return;
-        case 'body':
+        case "body":
           phase = _inBodyPhase;
           return;
-        case 'frameset':
+        case "frameset":
           phase = _inFramesetPhase;
           return;
-        case 'html':
+        case "html":
           phase = _beforeHeadPhase;
           return;
       }
@@ -569,11 +569,11 @@
   /// Generic RCDATA/RAWTEXT Parsing algorithm
   /// [contentType] - RCDATA or RAWTEXT
   void parseRCDataRawtext(Token token, String contentType) {
-    assert(contentType == 'RAWTEXT' || contentType == 'RCDATA');
+    assert(contentType == "RAWTEXT" || contentType == "RCDATA");
 
     tree.insertElement(token);
 
-    if (contentType == 'RAWTEXT') {
+    if (contentType == "RAWTEXT") {
       tokenizer.state = tokenizer.rawtextState;
     } else {
       tokenizer.state = tokenizer.rcdataState;
@@ -615,7 +615,7 @@
   }
 
   Token processDoctype(DoctypeToken token) {
-    parser.parseError(token.span, 'unexpected-doctype');
+    parser.parseError(token.span, "unexpected-doctype");
     return null;
   }
 
@@ -634,8 +634,8 @@
   }
 
   Token startTagHtml(StartTagToken token) {
-    if (parser.firstStartTag == false && token.name == 'html') {
-      parser.parseError(token.span, 'non-html-root');
+    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().
@@ -653,7 +653,7 @@
 
   /// Helper method for popping openElements.
   void popOpenElementsUntil(EndTagToken token) {
-    var name = token.name;
+    String name = token.name;
     var node = tree.openElements.removeLast();
     while (node.localName != name) {
       node = tree.openElements.removeLast();
@@ -667,157 +667,152 @@
 class InitialPhase extends Phase {
   InitialPhase(parser) : super(parser);
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     return null;
   }
 
-  @override
   Token processComment(CommentToken token) {
     tree.insertComment(token, tree.document);
     return null;
   }
 
-  @override
   Token processDoctype(DoctypeToken token) {
     var name = token.name;
-    var publicId = token.publicId;
+    String publicId = token.publicId;
     var systemId = token.systemId;
     var correct = token.correct;
 
-    if ((name != 'html' ||
+    if ((name != "html" ||
         publicId != null ||
-        systemId != null && systemId != 'about:legacy-compat')) {
-      parser.parseError(token.span, 'unknown-doctype');
+        systemId != null && systemId != "about:legacy-compat")) {
+      parser.parseError(token.span, "unknown-doctype");
     }
 
-    publicId ??= '';
+    if (publicId == null) {
+      publicId = "";
+    }
 
     tree.insertDoctype(token);
 
-    if (publicId != '') {
+    if (publicId != "") {
       publicId = asciiUpper2Lower(publicId);
     }
 
     if (!correct ||
-        token.name != 'html' ||
+        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//',
+          "+//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//'
+          "-//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'
+          "-//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//'
+              "-//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';
+                "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//'
+          "-//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//'
+              "-//w3c//dtd html 4.01 frameset//",
+              "-//w3c//dtd html 4.01 transitional//"
             ]) &&
             systemId != null) {
-      parser.compatMode = 'limited quirks';
+      parser.compatMode = "limited quirks";
     }
     parser.phase = parser._beforeHtmlPhase;
     return null;
   }
 
   void anythingElse() {
-    parser.compatMode = 'quirks';
+    parser.compatMode = "quirks";
     parser.phase = parser._beforeHtmlPhase;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    parser.parseError(token.span, 'expected-doctype-but-got-chars');
+    parser.parseError(token.span, "expected-doctype-but-got-chars");
     anythingElse();
     return token;
   }
 
-  @override
   Token processStartTag(StartTagToken token) {
     parser.parseError(
-        token.span, 'expected-doctype-but-got-start-tag', {'name': token.name});
+        token.span, "expected-doctype-but-got-start-tag", {"name": token.name});
     anythingElse();
     return token;
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     parser.parseError(
-        token.span, 'expected-doctype-but-got-end-tag', {'name': token.name});
+        token.span, "expected-doctype-but-got-end-tag", {"name": token.name});
     anythingElse();
     return token;
   }
 
-  @override
   bool processEOF() {
-    parser.parseError(parser._lastSpan, 'expected-doctype-but-got-eof');
+    parser.parseError(parser._lastSpan, "expected-doctype-but-got-eof");
     anythingElse();
     return true;
   }
@@ -829,56 +824,49 @@
   // helper methods
   void insertHtmlElement() {
     tree.insertRoot(
-        StartTagToken('html', data: LinkedHashMap<dynamic, String>()));
+        StartTagToken("html", data: LinkedHashMap<dynamic, String>()));
     parser.phase = parser._beforeHeadPhase;
   }
 
   // other
-  @override
   bool processEOF() {
     insertHtmlElement();
     return true;
   }
 
-  @override
   Token processComment(CommentToken token) {
     tree.insertComment(token, tree.document);
     return null;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     return null;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     insertHtmlElement();
     return token;
   }
 
-  @override
-  @override
   Token processStartTag(StartTagToken token) {
-    if (token.name == 'html') {
+    if (token.name == "html") {
       parser.firstStartTag = true;
     }
     insertHtmlElement();
     return token;
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'head':
-      case 'body':
-      case 'html':
-      case 'br':
+      case "head":
+      case "body":
+      case "html":
+      case "br":
         insertHtmlElement();
         return token;
       default:
         parser.parseError(
-            token.span, 'unexpected-end-tag-before-html', {'name': token.name});
+            token.span, "unexpected-end-tag-before-html", {"name": token.name});
         return null;
     }
   }
@@ -887,7 +875,6 @@
 class BeforeHeadPhase extends Phase {
   BeforeHeadPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
       case 'html':
@@ -900,13 +887,12 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'head':
-      case 'body':
-      case 'html':
-      case 'br':
+      case "head":
+      case "body":
+      case "html":
+      case "br":
         return endTagImplyHead(token);
       default:
         endTagOther(token);
@@ -914,24 +900,20 @@
     }
   }
 
-  @override
   bool processEOF() {
-    startTagHead(StartTagToken('head', data: LinkedHashMap<dynamic, String>()));
+    startTagHead(StartTagToken("head", data: LinkedHashMap<dynamic, String>()));
     return true;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     return null;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    startTagHead(StartTagToken('head', data: LinkedHashMap<dynamic, String>()));
+    startTagHead(StartTagToken("head", data: LinkedHashMap<dynamic, String>()));
     return token;
   }
 
-  @override
   Token startTagHtml(StartTagToken token) {
     return parser._inBodyPhase.processStartTag(token);
   }
@@ -943,51 +925,50 @@
   }
 
   Token startTagOther(StartTagToken token) {
-    startTagHead(StartTagToken('head', data: LinkedHashMap<dynamic, String>()));
+    startTagHead(StartTagToken("head", data: LinkedHashMap<dynamic, String>()));
     return token;
   }
 
   Token endTagImplyHead(EndTagToken token) {
-    startTagHead(StartTagToken('head', data: LinkedHashMap<dynamic, String>()));
+    startTagHead(StartTagToken("head", data: LinkedHashMap<dynamic, String>()));
     return token;
   }
 
   void endTagOther(EndTagToken token) {
     parser.parseError(
-        token.span, 'end-tag-after-implied-root', {'name': token.name});
+        token.span, "end-tag-after-implied-root", {"name": token.name});
   }
 }
 
 class InHeadPhase extends Phase {
   InHeadPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'title':
+      case "title":
         startTagTitle(token);
         return null;
-      case 'noscript':
-      case 'noframes':
-      case 'style':
+      case "noscript":
+      case "noframes":
+      case "style":
         startTagNoScriptNoFramesStyle(token);
         return null;
-      case 'script':
+      case "script":
         startTagScript(token);
         return null;
-      case 'base':
-      case 'basefont':
-      case 'bgsound':
-      case 'command':
-      case 'link':
+      case "base":
+      case "basefont":
+      case "bgsound":
+      case "command":
+      case "link":
         startTagBaseLinkCommand(token);
         return null;
-      case 'meta':
+      case "meta":
         startTagMeta(token);
         return null;
-      case 'head':
+      case "head":
         startTagHead(token);
         return null;
       default:
@@ -995,15 +976,14 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'head':
+      case "head":
         endTagHead(token);
         return null;
-      case 'br':
-      case 'html':
-      case 'body':
+      case "br":
+      case "html":
+      case "body":
         return endTagHtmlBodyBr(token);
       default:
         endTagOther(token);
@@ -1012,25 +992,22 @@
   }
 
   // the real thing
-  @override
   bool processEOF() {
     anythingElse();
     return true;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     anythingElse();
     return token;
   }
 
-  @override
   Token startTagHtml(StartTagToken token) {
     return parser._inBodyPhase.processStartTag(token);
   }
 
   void startTagHead(StartTagToken token) {
-    parser.parseError(token.span, 'two-heads-are-not-better-than-one');
+    parser.parseError(token.span, "two-heads-are-not-better-than-one");
   }
 
   void startTagBaseLinkCommand(StartTagToken token) {
@@ -1046,8 +1023,8 @@
 
     var attributes = token.data;
     if (!parser.tokenizer.stream.charEncodingCertain) {
-      var charset = attributes['charset'];
-      var content = attributes['content'];
+      var charset = attributes["charset"];
+      var content = attributes["content"];
       if (charset != null) {
         parser.tokenizer.stream.changeEncoding(charset);
       } else if (content != null) {
@@ -1059,12 +1036,12 @@
   }
 
   void startTagTitle(StartTagToken token) {
-    parser.parseRCDataRawtext(token, 'RCDATA');
+    parser.parseRCDataRawtext(token, "RCDATA");
   }
 
   void startTagNoScriptNoFramesStyle(StartTagToken token) {
     // Need to decide whether to implement the scripting-disabled case
-    parser.parseRCDataRawtext(token, 'RAWTEXT');
+    parser.parseRCDataRawtext(token, "RAWTEXT");
   }
 
   void startTagScript(StartTagToken token) {
@@ -1081,7 +1058,7 @@
 
   void endTagHead(EndTagToken token) {
     var node = parser.tree.openElements.removeLast();
-    assert(node.localName == 'head');
+    assert(node.localName == "head");
     node.endSourceSpan = token.span;
     parser.phase = parser._afterHeadPhase;
   }
@@ -1092,11 +1069,11 @@
   }
 
   void endTagOther(EndTagToken token) {
-    parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
   }
 
   void anythingElse() {
-    endTagHead(EndTagToken('head'));
+    endTagHead(EndTagToken("head"));
   }
 }
 
@@ -1108,29 +1085,28 @@
 class AfterHeadPhase extends Phase {
   AfterHeadPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'body':
+      case "body":
         startTagBody(token);
         return null;
-      case 'frameset':
+      case "frameset":
         startTagFrameset(token);
         return null;
-      case 'base':
-      case 'basefont':
-      case 'bgsound':
-      case 'link':
-      case 'meta':
-      case 'noframes':
-      case 'script':
-      case 'style':
-      case 'title':
+      case "base":
+      case "basefont":
+      case "bgsound":
+      case "link":
+      case "meta":
+      case "noframes":
+      case "script":
+      case "style":
+      case "title":
         startTagFromHead(token);
         return null;
-      case 'head':
+      case "head":
         startTagHead(token);
         return null;
       default:
@@ -1138,12 +1114,11 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'body':
-      case 'html':
-      case 'br':
+      case "body":
+      case "html":
+      case "br":
         return endTagHtmlBodyBr(token);
       default:
         endTagOther(token);
@@ -1151,19 +1126,16 @@
     }
   }
 
-  @override
   bool processEOF() {
     anythingElse();
     return true;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     anythingElse();
     return token;
   }
 
-  @override
   Token startTagHtml(StartTagToken token) {
     return parser._inBodyPhase.processStartTag(token);
   }
@@ -1180,12 +1152,12 @@
   }
 
   void startTagFromHead(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-start-tag-out-of-my-head',
-        {'name': token.name});
+    parser.parseError(token.span, "unexpected-start-tag-out-of-my-head",
+        {"name": token.name});
     tree.openElements.add(tree.headPointer);
     parser._inHeadPhase.processStartTag(token);
     for (var node in tree.openElements.reversed) {
-      if (node.localName == 'head') {
+      if (node.localName == "head") {
         tree.openElements.remove(node);
         break;
       }
@@ -1193,7 +1165,7 @@
   }
 
   void startTagHead(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-start-tag', {'name': token.name});
+    parser.parseError(token.span, "unexpected-start-tag", {"name": token.name});
   }
 
   Token startTagOther(StartTagToken token) {
@@ -1207,12 +1179,12 @@
   }
 
   void endTagOther(EndTagToken token) {
-    parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
   }
 
   void anythingElse() {
     tree.insertElement(
-        StartTagToken('body', data: LinkedHashMap<dynamic, String>()));
+        StartTagToken("body", data: LinkedHashMap<dynamic, String>()));
     parser.phase = parser._inBodyPhase;
     parser.framesetOK = true;
   }
@@ -1227,172 +1199,171 @@
   // the really-really-really-very crazy mode
   InBodyPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      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':
+      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':
+      case "body":
         startTagBody(token);
         return null;
-      case 'frameset':
+      case "frameset":
         startTagFrameset(token);
         return null;
-      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 'menu':
-      case 'nav':
-      case 'ol':
-      case 'p':
-      case 'section':
-      case 'summary':
-      case 'ul':
+      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 "menu":
+      case "nav":
+      case "ol":
+      case "p":
+      case "section":
+      case "summary":
+      case "ul":
         startTagCloseP(token);
         return null;
       // headingElements
-      case 'h1':
-      case 'h2':
-      case 'h3':
-      case 'h4':
-      case 'h5':
-      case 'h6':
+      case "h1":
+      case "h2":
+      case "h3":
+      case "h4":
+      case "h5":
+      case "h6":
         startTagHeading(token);
         return null;
-      case 'pre':
-      case 'listing':
+      case "pre":
+      case "listing":
         startTagPreListing(token);
         return null;
-      case 'form':
+      case "form":
         startTagForm(token);
         return null;
-      case 'li':
-      case 'dd':
-      case 'dt':
+      case "li":
+      case "dd":
+      case "dt":
         startTagListItem(token);
         return null;
-      case 'plaintext':
+      case "plaintext":
         startTagPlaintext(token);
         return null;
-      case 'a':
+      case "a":
         startTagA(token);
         return null;
-      case 'b':
-      case 'big':
-      case 'code':
-      case 'em':
-      case 'font':
-      case 'i':
-      case 's':
-      case 'small':
-      case 'strike':
-      case 'strong':
-      case 'tt':
-      case 'u':
+      case "b":
+      case "big":
+      case "code":
+      case "em":
+      case "font":
+      case "i":
+      case "s":
+      case "small":
+      case "strike":
+      case "strong":
+      case "tt":
+      case "u":
         startTagFormatting(token);
         return null;
-      case 'nobr':
+      case "nobr":
         startTagNobr(token);
         return null;
-      case 'button':
+      case "button":
         return startTagButton(token);
-      case 'applet':
-      case 'marquee':
-      case 'object':
+      case "applet":
+      case "marquee":
+      case "object":
         startTagAppletMarqueeObject(token);
         return null;
-      case 'xmp':
+      case "xmp":
         startTagXmp(token);
         return null;
-      case 'table':
+      case "table":
         startTagTable(token);
         return null;
-      case 'area':
-      case 'br':
-      case 'embed':
-      case 'img':
-      case 'keygen':
-      case 'wbr':
+      case "area":
+      case "br":
+      case "embed":
+      case "img":
+      case "keygen":
+      case "wbr":
         startTagVoidFormatting(token);
         return null;
-      case 'param':
-      case 'source':
-      case 'track':
+      case "param":
+      case "source":
+      case "track":
         startTagParamSource(token);
         return null;
-      case 'input':
+      case "input":
         startTagInput(token);
         return null;
-      case 'hr':
+      case "hr":
         startTagHr(token);
         return null;
-      case 'image':
+      case "image":
         startTagImage(token);
         return null;
-      case 'isindex':
+      case "isindex":
         startTagIsIndex(token);
         return null;
-      case 'textarea':
+      case "textarea":
         startTagTextarea(token);
         return null;
-      case 'iframe':
+      case "iframe":
         startTagIFrame(token);
         return null;
-      case 'noembed':
-      case 'noscript':
+      case "noembed":
+      case "noscript":
         startTagRawtext(token);
         return null;
-      case 'select':
+      case "select":
         startTagSelect(token);
         return null;
-      case 'rp':
-      case 'rt':
+      case "rp":
+      case "rt":
         startTagRpRt(token);
         return null;
-      case 'option':
-      case 'optgroup':
+      case "option":
+      case "optgroup":
         startTagOpt(token);
         return null;
-      case 'math':
+      case "math":
         startTagMath(token);
         return null;
-      case 'svg':
+      case "svg":
         startTagSvg(token);
         return null;
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'frame':
-      case 'head':
-      case 'tbody':
-      case 'td':
-      case 'tfoot':
-      case 'th':
-      case 'thead':
-      case 'tr':
+      case "caption":
+      case "col":
+      case "colgroup":
+      case "frame":
+      case "head":
+      case "tbody":
+      case "td":
+      case "tfoot":
+      case "th":
+      case "thead":
+      case "tr":
         startTagMisplaced(token);
         return null;
       default:
@@ -1400,82 +1371,80 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'body':
+      case "body":
         endTagBody(token);
         return null;
-      case 'html':
+      case "html":
         return endTagHtml(token);
-      case 'address':
-      case 'article':
-      case 'aside':
-      case 'blockquote':
-      case 'button':
-      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':
+      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":
         endTagBlock(token);
         return null;
-      case 'form':
+      case "form":
         endTagForm(token);
         return null;
-      case 'p':
+      case "p":
         endTagP(token);
         return null;
-      case 'dd':
-      case 'dt':
-      case 'li':
+      case "dd":
+      case "dt":
+      case "li":
         endTagListItem(token);
         return null;
       // headingElements
-      case 'h1':
-      case 'h2':
-      case 'h3':
-      case 'h4':
-      case 'h5':
-      case 'h6':
+      case "h1":
+      case "h2":
+      case "h3":
+      case "h4":
+      case "h5":
+      case "h6":
         endTagHeading(token);
         return null;
-      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':
+      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":
         endTagFormatting(token);
         return null;
-      case 'applet':
-      case 'marquee':
-      case 'object':
+      case "applet":
+      case "marquee":
+      case "object":
         endTagAppletMarqueeObject(token);
         return null;
-      case 'br':
+      case "br":
         endTagBr(token);
         return null;
       default:
@@ -1522,25 +1491,24 @@
   }
 
   // the real deal
-  @override
   bool processEOF() {
     for (var node in tree.openElements.reversed) {
       switch (node.localName) {
-        case 'dd':
-        case 'dt':
-        case 'li':
-        case 'p':
-        case 'tbody':
-        case 'td':
-        case 'tfoot':
-        case 'th':
-        case 'thead':
-        case 'tr':
-        case 'body':
-        case 'html':
+        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');
+      parser.parseError(node.sourceSpan, "expected-closing-tag-but-got-eof");
       break;
     }
     //Stop parsing
@@ -1552,9 +1520,9 @@
     // want to drop leading newlines
     var data = token.data;
     dropNewline = false;
-    if (data.startsWith('\n')) {
+    if (data.startsWith("\n")) {
       var lastOpen = tree.openElements.last;
-      if (const ['pre', 'listing', 'textarea'].contains(lastOpen.localName) &&
+      if (const ["pre", "listing", "textarea"].contains(lastOpen.localName) &&
           !lastOpen.hasContent()) {
         data = data.substring(1);
       }
@@ -1565,9 +1533,8 @@
     }
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    if (token.data == '\u0000') {
+    if (token.data == "\u0000") {
       //The tokenizer should always emit null on its own
       return null;
     }
@@ -1579,7 +1546,6 @@
     return null;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     if (dropNewline) {
       processSpaceCharactersDropNewline(token);
@@ -1595,9 +1561,9 @@
   }
 
   void startTagBody(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-start-tag', {'name': 'body'});
+    parser.parseError(token.span, "unexpected-start-tag", {"name": "body"});
     if (tree.openElements.length == 1 ||
-        tree.openElements[1].localName != 'body') {
+        tree.openElements[1].localName != "body") {
       assert(parser.innerHTMLMode);
     } else {
       parser.framesetOK = false;
@@ -1608,15 +1574,15 @@
   }
 
   void startTagFrameset(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-start-tag', {'name': 'frameset'});
+    parser.parseError(token.span, "unexpected-start-tag", {"name": "frameset"});
     if ((tree.openElements.length == 1 ||
-        tree.openElements[1].localName != 'body')) {
+        tree.openElements[1].localName != "body")) {
       assert(parser.innerHTMLMode);
     } else if (parser.framesetOK) {
       if (tree.openElements[1].parentNode != null) {
         tree.openElements[1].parentNode.nodes.remove(tree.openElements[1]);
       }
-      while (tree.openElements.last.localName != 'html') {
+      while (tree.openElements.last.localName != "html") {
         tree.openElements.removeLast();
       }
       tree.insertElement(token);
@@ -1625,15 +1591,15 @@
   }
 
   void startTagCloseP(StartTagToken token) {
-    if (tree.elementInScope('p', variant: 'button')) {
-      endTagP(EndTagToken('p'));
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(EndTagToken("p"));
     }
     tree.insertElement(token);
   }
 
   void startTagPreListing(StartTagToken token) {
-    if (tree.elementInScope('p', variant: 'button')) {
-      endTagP(EndTagToken('p'));
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(EndTagToken("p"));
     }
     tree.insertElement(token);
     parser.framesetOK = false;
@@ -1642,10 +1608,10 @@
 
   void startTagForm(StartTagToken token) {
     if (tree.formPointer != null) {
-      parser.parseError(token.span, 'unexpected-start-tag', {'name': 'form'});
+      parser.parseError(token.span, "unexpected-start-tag", {"name": "form"});
     } else {
-      if (tree.elementInScope('p', variant: 'button')) {
-        endTagP(EndTagToken('p'));
+      if (tree.elementInScope("p", variant: "button")) {
+        endTagP(EndTagToken("p"));
       }
       tree.insertElement(token);
       tree.formPointer = tree.openElements.last;
@@ -1656,9 +1622,9 @@
     parser.framesetOK = false;
 
     final stopNamesMap = const {
-      'li': ['li'],
-      'dt': ['dt', 'dd'],
-      'dd': ['dt', 'dd']
+      "li": ["li"],
+      "dt": ["dt", "dd"],
+      "dd": ["dt", "dd"]
     };
     var stopNames = stopNamesMap[token.name];
     for (var node in tree.openElements.reversed) {
@@ -1667,44 +1633,44 @@
         break;
       }
       if (specialElements.contains(getElementNameTuple(node)) &&
-          !const ['address', 'div', 'p'].contains(node.localName)) {
+          !const ["address", "div", "p"].contains(node.localName)) {
         break;
       }
     }
 
-    if (tree.elementInScope('p', variant: 'button')) {
-      parser.phase.processEndTag(EndTagToken('p'));
+    if (tree.elementInScope("p", variant: "button")) {
+      parser.phase.processEndTag(EndTagToken("p"));
     }
 
     tree.insertElement(token);
   }
 
   void startTagPlaintext(StartTagToken token) {
-    if (tree.elementInScope('p', variant: 'button')) {
-      endTagP(EndTagToken('p'));
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(EndTagToken("p"));
     }
     tree.insertElement(token);
     parser.tokenizer.state = parser.tokenizer.plaintextState;
   }
 
   void startTagHeading(StartTagToken token) {
-    if (tree.elementInScope('p', variant: 'button')) {
-      endTagP(EndTagToken('p'));
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(EndTagToken("p"));
     }
     if (headingElements.contains(tree.openElements.last.localName)) {
       parser
-          .parseError(token.span, 'unexpected-start-tag', {'name': token.name});
+          .parseError(token.span, "unexpected-start-tag", {"name": token.name});
       tree.openElements.removeLast();
     }
     tree.insertElement(token);
   }
 
   void startTagA(StartTagToken token) {
-    var afeAElement = tree.elementInActiveFormattingElements('a');
+    var afeAElement = tree.elementInActiveFormattingElements("a");
     if (afeAElement != null) {
-      parser.parseError(token.span, 'unexpected-start-tag-implies-end-tag',
-          {'startName': 'a', 'endName': 'a'});
-      endTagFormatting(EndTagToken('a'));
+      parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+          {"startName": "a", "endName": "a"});
+      endTagFormatting(EndTagToken("a"));
       tree.openElements.remove(afeAElement);
       tree.activeFormattingElements.remove(afeAElement);
     }
@@ -1719,10 +1685,10 @@
 
   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(EndTagToken('nobr'));
+    if (tree.elementInScope("nobr")) {
+      parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+          {"startName": "nobr", "endName": "nobr"});
+      processEndTag(EndTagToken("nobr"));
       // XXX Need tests that trigger the following
       tree.reconstructActiveFormattingElements();
     }
@@ -1730,10 +1696,10 @@
   }
 
   Token startTagButton(StartTagToken token) {
-    if (tree.elementInScope('button')) {
-      parser.parseError(token.span, 'unexpected-start-tag-implies-end-tag',
-          {'startName': 'button', 'endName': 'button'});
-      processEndTag(EndTagToken('button'));
+    if (tree.elementInScope("button")) {
+      parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+          {"startName": "button", "endName": "button"});
+      processEndTag(EndTagToken("button"));
       return token;
     } else {
       tree.reconstructActiveFormattingElements();
@@ -1751,18 +1717,18 @@
   }
 
   void startTagXmp(StartTagToken token) {
-    if (tree.elementInScope('p', variant: 'button')) {
-      endTagP(EndTagToken('p'));
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(EndTagToken("p"));
     }
     tree.reconstructActiveFormattingElements();
     parser.framesetOK = false;
-    parser.parseRCDataRawtext(token, 'RAWTEXT');
+    parser.parseRCDataRawtext(token, "RAWTEXT");
   }
 
   void startTagTable(StartTagToken token) {
-    if (parser.compatMode != 'quirks') {
-      if (tree.elementInScope('p', variant: 'button')) {
-        processEndTag(EndTagToken('p'));
+    if (parser.compatMode != "quirks") {
+      if (tree.elementInScope("p", variant: "button")) {
+        processEndTag(EndTagToken("p"));
       }
     }
     tree.insertElement(token);
@@ -1781,7 +1747,7 @@
   void startTagInput(StartTagToken token) {
     var savedFramesetOK = parser.framesetOK;
     startTagVoidFormatting(token);
-    if (asciiUpper2Lower(token.data['type']) == 'hidden') {
+    if (asciiUpper2Lower(token.data["type"]) == "hidden") {
       //input type=hidden doesn't change framesetOK
       parser.framesetOK = savedFramesetOK;
     }
@@ -1794,8 +1760,8 @@
   }
 
   void startTagHr(StartTagToken token) {
-    if (tree.elementInScope('p', variant: 'button')) {
-      endTagP(EndTagToken('p'));
+    if (tree.elementInScope("p", variant: "button")) {
+      endTagP(EndTagToken("p"));
     }
     tree.insertElement(token);
     tree.openElements.removeLast();
@@ -1805,41 +1771,43 @@
 
   void startTagImage(StartTagToken token) {
     // No really...
-    parser.parseError(token.span, 'unexpected-start-tag-treated-as',
-        {'originalName': 'image', 'newName': 'img'});
+    parser.parseError(token.span, "unexpected-start-tag-treated-as",
+        {"originalName": "image", "newName": "img"});
     processStartTag(
-        StartTagToken('img', data: token.data, selfClosing: token.selfClosing));
+        StartTagToken("img", data: token.data, selfClosing: token.selfClosing));
   }
 
   void startTagIsIndex(StartTagToken token) {
-    parser.parseError(token.span, 'deprecated-tag', {'name': 'isindex'});
+    parser.parseError(token.span, "deprecated-tag", {"name": "isindex"});
     if (tree.formPointer != null) {
       return;
     }
-    var formAttrs = <dynamic, String>{};
-    var dataAction = token.data['action'];
+    var formAttrs = LinkedHashMap<dynamic, String>();
+    var dataAction = token.data["action"];
     if (dataAction != null) {
-      formAttrs['action'] = dataAction;
+      formAttrs["action"] = dataAction;
     }
-    processStartTag(StartTagToken('form', data: formAttrs));
+    processStartTag(StartTagToken("form", data: formAttrs));
     processStartTag(
-        StartTagToken('hr', data: LinkedHashMap<dynamic, String>()));
+        StartTagToken("hr", data: LinkedHashMap<dynamic, String>()));
     processStartTag(
-        StartTagToken('label', data: LinkedHashMap<dynamic, String>()));
+        StartTagToken("label", data: LinkedHashMap<dynamic, String>()));
     // XXX Localization ...
-    var prompt = token.data['prompt'];
-    prompt ??= 'This is a searchable index. Enter search keywords: ';
+    var prompt = token.data["prompt"];
+    if (prompt == null) {
+      prompt = "This is a searchable index. Enter search keywords: ";
+    }
     processCharacters(CharactersToken(prompt));
     var attributes = LinkedHashMap<dynamic, String>.from(token.data);
     attributes.remove('action');
     attributes.remove('prompt');
-    attributes['name'] = 'isindex';
-    processStartTag(StartTagToken('input',
+    attributes["name"] = "isindex";
+    processStartTag(StartTagToken("input",
         data: attributes, selfClosing: token.selfClosing));
-    processEndTag(EndTagToken('label'));
+    processEndTag(EndTagToken("label"));
     processStartTag(
-        StartTagToken('hr', data: LinkedHashMap<dynamic, String>()));
-    processEndTag(EndTagToken('form'));
+        StartTagToken("hr", data: LinkedHashMap<dynamic, String>()));
+    processEndTag(EndTagToken("form"));
   }
 
   void startTagTextarea(StartTagToken token) {
@@ -1856,12 +1824,12 @@
 
   /// iframe, noembed noframes, noscript(if scripting enabled).
   void startTagRawtext(StartTagToken token) {
-    parser.parseRCDataRawtext(token, 'RAWTEXT');
+    parser.parseRCDataRawtext(token, "RAWTEXT");
   }
 
   void startTagOpt(StartTagToken token) {
-    if (tree.openElements.last.localName == 'option') {
-      parser.phase.processEndTag(EndTagToken('option'));
+    if (tree.openElements.last.localName == "option") {
+      parser.phase.processEndTag(EndTagToken("option"));
     }
     tree.reconstructActiveFormattingElements();
     parser.tree.insertElement(token);
@@ -1885,10 +1853,10 @@
   }
 
   void startTagRpRt(StartTagToken token) {
-    if (tree.elementInScope('ruby')) {
+    if (tree.elementInScope("ruby")) {
       tree.generateImpliedEndTags();
       var last = tree.openElements.last;
-      if (last.localName != 'ruby') {
+      if (last.localName != "ruby") {
         parser.parseError(last.sourceSpan, 'undefined-error');
       }
     }
@@ -1930,7 +1898,7 @@
   /// "tr", "noscript"
   void startTagMisplaced(StartTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-start-tag-ignored', {'name': token.name});
+        token.span, "unexpected-start-tag-ignored", {"name": token.name});
   }
 
   Token startTagOther(StartTagToken token) {
@@ -1940,50 +1908,50 @@
   }
 
   void endTagP(EndTagToken token) {
-    if (!tree.elementInScope('p', variant: 'button')) {
+    if (!tree.elementInScope("p", variant: "button")) {
       startTagCloseP(
-          StartTagToken('p', data: LinkedHashMap<dynamic, String>()));
-      parser.parseError(token.span, 'unexpected-end-tag', {'name': 'p'});
-      endTagP(EndTagToken('p'));
+          StartTagToken("p", data: LinkedHashMap<dynamic, String>()));
+      parser.parseError(token.span, "unexpected-end-tag", {"name": "p"});
+      endTagP(EndTagToken("p"));
     } else {
-      tree.generateImpliedEndTags('p');
-      if (tree.openElements.last.localName != 'p') {
-        parser.parseError(token.span, 'unexpected-end-tag', {'name': 'p'});
+      tree.generateImpliedEndTags("p");
+      if (tree.openElements.last.localName != "p") {
+        parser.parseError(token.span, "unexpected-end-tag", {"name": "p"});
       }
       popOpenElementsUntil(token);
     }
   }
 
   void endTagBody(EndTagToken token) {
-    if (!tree.elementInScope('body')) {
+    if (!tree.elementInScope("body")) {
       parser.parseError(token.span, 'undefined-error');
       return;
-    } else if (tree.openElements.last.localName == 'body') {
+    } else if (tree.openElements.last.localName == "body") {
       tree.openElements.last.endSourceSpan = token.span;
     } else {
-      for (var node in slice(tree.openElements, 2)) {
+      for (Element node in slice(tree.openElements, 2)) {
         switch (node.localName) {
-          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':
+          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',
-            {'gotName': 'body', 'expectedName': node.localName});
+        parser.parseError(token.span, "expected-one-end-tag-but-got-another",
+            {"gotName": "body", "expectedName": node.localName});
         break;
       }
     }
@@ -1992,8 +1960,8 @@
 
   Token endTagHtml(EndTagToken token) {
     //We repeat the test for the body end tag token being ignored here
-    if (tree.elementInScope('body')) {
-      endTagBody(EndTagToken('body'));
+    if (tree.elementInScope("body")) {
+      endTagBody(EndTagToken("body"));
       return token;
     }
     return null;
@@ -2001,7 +1969,7 @@
 
   void endTagBlock(EndTagToken token) {
     //Put us back in the right whitespace handling mode
-    if (token.name == 'pre') {
+    if (token.name == "pre") {
       dropNewline = false;
     }
     var inScope = tree.elementInScope(token.name);
@@ -2009,7 +1977,7 @@
       tree.generateImpliedEndTags();
     }
     if (tree.openElements.last.localName != token.name) {
-      parser.parseError(token.span, 'end-tag-too-early', {'name': token.name});
+      parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
     }
     if (inScope) {
       popOpenElementsUntil(token);
@@ -2020,12 +1988,12 @@
     var node = tree.formPointer;
     tree.formPointer = null;
     if (node == null || !tree.elementInScope(node)) {
-      parser.parseError(token.span, 'unexpected-end-tag', {'name': 'form'});
+      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'});
+            token.span, "end-tag-too-early-ignored", {"name": "form"});
       }
       tree.openElements.remove(node);
       node.endSourceSpan = token.span;
@@ -2034,18 +2002,18 @@
 
   void endTagListItem(EndTagToken token) {
     String variant;
-    if (token.name == 'li') {
-      variant = 'list';
+    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});
+      parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
     } else {
       tree.generateImpliedEndTags(token.name);
       if (tree.openElements.last.localName != token.name) {
         parser
-            .parseError(token.span, 'end-tag-too-early', {'name': token.name});
+            .parseError(token.span, "end-tag-too-early", {"name": token.name});
       }
       popOpenElementsUntil(token);
     }
@@ -2059,12 +2027,12 @@
       }
     }
     if (tree.openElements.last.localName != token.name) {
-      parser.parseError(token.span, 'end-tag-too-early', {'name': token.name});
+      parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
     }
 
     for (var item in headingElements) {
       if (tree.elementInScope(item)) {
-        var node = tree.openElements.removeLast();
+        Element node = tree.openElements.removeLast();
         while (!headingElements.contains(node.localName)) {
           node = tree.openElements.removeLast();
         }
@@ -2083,7 +2051,7 @@
     // 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.
-    var outerLoopCounter = 0;
+    int outerLoopCounter = 0;
     while (outerLoopCounter < 8) {
       outerLoopCounter += 1;
 
@@ -2094,12 +2062,12 @@
           (tree.openElements.contains(formattingElement) &&
               !tree.elementInScope(formattingElement.localName))) {
         parser.parseError(
-            token.span, 'adoption-agency-1.1', {'name': token.name});
+            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});
+            token.span, "adoption-agency-1.2", {"name": token.name});
         tree.activeFormattingElements.remove(formattingElement);
         return;
       }
@@ -2107,14 +2075,14 @@
       // Step 1 paragraph 3
       if (formattingElement != tree.openElements.last) {
         parser.parseError(
-            token.span, 'adoption-agency-1.3', {'name': token.name});
+            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;
-      for (var element in slice(tree.openElements, afeIndex)) {
+      for (Node element in slice(tree.openElements, afeIndex)) {
         if (specialElements.contains(getElementNameTuple(element))) {
           furthestBlock = element;
           break;
@@ -2122,7 +2090,7 @@
       }
       // Step 3
       if (furthestBlock == null) {
-        var element = tree.openElements.removeLast();
+        Element element = tree.openElements.removeLast();
         while (element != formattingElement) {
           element = tree.openElements.removeLast();
         }
@@ -2143,9 +2111,9 @@
       var bookmark = tree.activeFormattingElements.indexOf(formattingElement);
 
       // Step 6
-      var lastNode = furthestBlock;
+      Node lastNode = furthestBlock;
       var node = furthestBlock;
-      var innerLoopCounter = 0;
+      int innerLoopCounter = 0;
 
       var index = tree.openElements.indexOf(node);
       while (innerLoopCounter < 3) {
@@ -2194,7 +2162,7 @@
         lastNode.parentNode.nodes.remove(lastNode);
       }
 
-      if (const ['table', 'tbody', 'tfoot', 'thead', 'tr']
+      if (const ["table", "tbody", "tfoot", "thead", "tr"]
           .contains(commonAncestor.localName)) {
         var nodePos = tree.getTableMisnestedNodePosition();
         nodePos[0].insertBefore(lastNode, nodePos[1]);
@@ -2228,7 +2196,7 @@
       tree.generateImpliedEndTags();
     }
     if (tree.openElements.last.localName != token.name) {
-      parser.parseError(token.span, 'end-tag-too-early', {'name': token.name});
+      parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
     }
     if (tree.elementInScope(token.name)) {
       popOpenElementsUntil(token);
@@ -2237,11 +2205,11 @@
   }
 
   void endTagBr(EndTagToken token) {
-    parser.parseError(token.span, 'unexpected-end-tag-treated-as',
-        {'originalName': 'br', 'newName': 'br element'});
+    parser.parseError(token.span, "unexpected-end-tag-treated-as",
+        {"originalName": "br", "newName": "br element"});
     tree.reconstructActiveFormattingElements();
     tree.insertElement(
-        StartTagToken('br', data: LinkedHashMap<dynamic, String>()));
+        StartTagToken("br", data: LinkedHashMap<dynamic, String>()));
     tree.openElements.removeLast();
   }
 
@@ -2251,7 +2219,7 @@
         tree.generateImpliedEndTags(token.name);
         if (tree.openElements.last.localName != token.name) {
           parser.parseError(
-              token.span, 'unexpected-end-tag', {'name': token.name});
+              token.span, "unexpected-end-tag", {"name": token.name});
         }
         while (tree.openElements.removeLast() != node) {
           // noop
@@ -2261,7 +2229,7 @@
       } else {
         if (specialElements.contains(getElementNameTuple(node))) {
           parser.parseError(
-              token.span, 'unexpected-end-tag', {'name': token.name});
+              token.span, "unexpected-end-tag", {"name": token.name});
           break;
         }
       }
@@ -2273,13 +2241,11 @@
   TextPhase(parser) : super(parser);
 
   // "Tried to process start tag %s in RCDATA/RAWTEXT mode"%token.name
-  @override
   // ignore: missing_return
   Token processStartTag(StartTagToken token) {
     assert(false);
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     if (token.name == 'script') {
       endTagScript(token);
@@ -2289,16 +2255,14 @@
     return null;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     tree.insertText(token.data, token.span);
     return null;
   }
 
-  @override
   bool processEOF() {
     var last = tree.openElements.last;
-    parser.parseError(last.sourceSpan, 'expected-named-closing-tag-but-got-eof',
+    parser.parseError(last.sourceSpan, "expected-named-closing-tag-but-got-eof",
         {'name': last.localName});
     tree.openElements.removeLast();
     parser.phase = parser.originalPhase;
@@ -2307,7 +2271,7 @@
 
   void endTagScript(EndTagToken token) {
     var node = tree.openElements.removeLast();
-    assert(node.localName == 'script');
+    assert(node.localName == "script");
     parser.phase = parser.originalPhase;
     //The rest of this method is all stuff that only happens if
     //document.write works
@@ -2323,37 +2287,36 @@
   // http://www.whatwg.org/specs/web-apps/current-work///in-table
   InTablePhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'caption':
+      case "caption":
         startTagCaption(token);
         return null;
-      case 'colgroup':
+      case "colgroup":
         startTagColgroup(token);
         return null;
-      case 'col':
+      case "col":
         return startTagCol(token);
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
+      case "tbody":
+      case "tfoot":
+      case "thead":
         startTagRowGroup(token);
         return null;
-      case 'td':
-      case 'th':
-      case 'tr':
+      case "td":
+      case "th":
+      case "tr":
         return startTagImplyTbody(token);
-      case 'table':
+      case "table":
         return startTagTable(token);
-      case 'style':
-      case 'script':
+      case "style":
+      case "script":
         return startTagStyleScript(token);
-      case 'input':
+      case "input":
         startTagInput(token);
         return null;
-      case 'form':
+      case "form":
         startTagForm(token);
         return null;
       default:
@@ -2362,23 +2325,22 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'table':
+      case "table":
         endTagTable(token);
         return null;
-      case 'body':
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'html':
-      case 'tbody':
-      case 'td':
-      case 'tfoot':
-      case 'th':
-      case 'thead':
-      case 'tr':
+      case "body":
+      case "caption":
+      case "col":
+      case "colgroup":
+      case "html":
+      case "tbody":
+      case "td":
+      case "tfoot":
+      case "th":
+      case "thead":
+      case "tr":
         endTagIgnore(token);
         return null;
       default:
@@ -2389,9 +2351,9 @@
 
   // helper methods
   void clearStackToTableContext() {
-    // 'clear the stack back to a table context'
-    while (tree.openElements.last.localName != 'table' &&
-        tree.openElements.last.localName != 'html') {
+    // "clear the stack back to a table context"
+    while (tree.openElements.last.localName != "table" &&
+        tree.openElements.last.localName != "html") {
       //parser.parseError(token.span, "unexpected-implied-end-tag-in-table",
       //  {"name":  tree.openElements.last.name})
       tree.openElements.removeLast();
@@ -2400,11 +2362,10 @@
   }
 
   // processing methods
-  @override
   bool processEOF() {
     var last = tree.openElements.last;
-    if (last.localName != 'html') {
-      parser.parseError(last.sourceSpan, 'eof-in-table');
+    if (last.localName != "html") {
+      parser.parseError(last.sourceSpan, "eof-in-table");
     } else {
       assert(parser.innerHTMLMode);
     }
@@ -2412,7 +2373,6 @@
     return false;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     var originalPhase = parser.phase;
     parser.phase = parser._inTableTextPhase;
@@ -2421,7 +2381,6 @@
     return null;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     var originalPhase = parser.phase;
     parser.phase = parser._inTableTextPhase;
@@ -2453,7 +2412,7 @@
 
   Token startTagCol(StartTagToken token) {
     startTagColgroup(
-        StartTagToken('colgroup', data: LinkedHashMap<dynamic, String>()));
+        StartTagToken("colgroup", data: LinkedHashMap<dynamic, String>()));
     return token;
   }
 
@@ -2465,14 +2424,14 @@
 
   Token startTagImplyTbody(StartTagToken token) {
     startTagRowGroup(
-        StartTagToken('tbody', data: LinkedHashMap<dynamic, String>()));
+        StartTagToken("tbody", data: LinkedHashMap<dynamic, String>()));
     return token;
   }
 
   Token startTagTable(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-start-tag-implies-end-tag',
-        {'startName': 'table', 'endName': 'table'});
-    parser.phase.processEndTag(EndTagToken('table'));
+    parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
+        {"startName": "table", "endName": "table"});
+    parser.phase.processEndTag(EndTagToken("table"));
     if (!parser.innerHTMLMode) {
       return token;
     }
@@ -2484,8 +2443,8 @@
   }
 
   void startTagInput(StartTagToken token) {
-    if (asciiUpper2Lower(token.data['type']) == 'hidden') {
-      parser.parseError(token.span, 'unexpected-hidden-input-in-table');
+    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();
@@ -2495,7 +2454,7 @@
   }
 
   void startTagForm(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-form-in-table');
+    parser.parseError(token.span, "unexpected-form-in-table");
     if (tree.formPointer == null) {
       tree.insertElement(token);
       tree.formPointer = tree.openElements.last;
@@ -2504,8 +2463,8 @@
   }
 
   void startTagOther(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-start-tag-implies-table-voodoo',
-        {'name': token.name});
+    parser.parseError(token.span, "unexpected-start-tag-implies-table-voodoo",
+        {"name": token.name});
     // Do the table magic!
     tree.insertFromTable = true;
     parser._inBodyPhase.processStartTag(token);
@@ -2513,14 +2472,14 @@
   }
 
   void endTagTable(EndTagToken token) {
-    if (tree.elementInScope('table', variant: 'table')) {
+    if (tree.elementInScope("table", variant: "table")) {
       tree.generateImpliedEndTags();
       var last = tree.openElements.last;
-      if (last.localName != 'table') {
-        parser.parseError(token.span, 'end-tag-too-early-named',
-            {'gotName': 'table', 'expectedName': last.localName});
+      if (last.localName != "table") {
+        parser.parseError(token.span, "end-tag-too-early-named",
+            {"gotName": "table", "expectedName": last.localName});
       }
-      while (tree.openElements.last.localName != 'table') {
+      while (tree.openElements.last.localName != "table") {
         tree.openElements.removeLast();
       }
       var node = tree.openElements.removeLast();
@@ -2529,17 +2488,17 @@
     } else {
       // innerHTML case
       assert(parser.innerHTMLMode);
-      parser.parseError(token.span, 'undefined-error');
+      parser.parseError(token.span, "undefined-error");
     }
   }
 
   void endTagIgnore(EndTagToken token) {
-    parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+    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});
+    parser.parseError(token.span, "unexpected-end-tag-implies-table-voodoo",
+        {"name": token.name});
     // Do the table magic!
     tree.insertFromTable = true;
     parser._inBodyPhase.processEndTag(token);
@@ -2574,30 +2533,26 @@
     characterTokens = <StringToken>[];
   }
 
-  @override
   Token processComment(CommentToken token) {
     flushCharacters();
     parser.phase = originalPhase;
     return token;
   }
 
-  @override
   bool processEOF() {
     flushCharacters();
     parser.phase = originalPhase;
     return true;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    if (token.data == '\u0000') {
+    if (token.data == "\u0000") {
       return null;
     }
     characterTokens.add(token);
     return null;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     //pretty sure we should never reach here
     characterTokens.add(token);
@@ -2605,14 +2560,12 @@
     return null;
   }
 
-  @override
   Token processStartTag(StartTagToken token) {
     flushCharacters();
     parser.phase = originalPhase;
     return token;
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     flushCharacters();
     parser.phase = originalPhase;
@@ -2624,44 +2577,42 @@
   // http://www.whatwg.org/specs/web-apps/current-work///in-caption
   InCaptionPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'tbody':
-      case 'td':
-      case 'tfoot':
-      case 'th':
-      case 'thead':
-      case 'tr':
+      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);
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'caption':
+      case "caption":
         endTagCaption(token);
         return null;
-      case 'table':
+      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':
+      case "body":
+      case "col":
+      case "colgroup":
+      case "html":
+      case "tbody":
+      case "td":
+      case "tfoot":
+      case "th":
+      case "thead":
+      case "tr":
         endTagIgnore(token);
         return null;
       default:
@@ -2670,25 +2621,23 @@
   }
 
   bool ignoreEndTagCaption() {
-    return !tree.elementInScope('caption', variant: 'table');
+    return !tree.elementInScope("caption", variant: "table");
   }
 
-  @override
   bool processEOF() {
     parser._inBodyPhase.processEOF();
     return false;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     return parser._inBodyPhase.processCharacters(token);
   }
 
   Token startTagTableElement(StartTagToken token) {
-    parser.parseError(token.span, 'undefined-error');
+    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(EndTagToken('caption'));
+    parser.phase.processEndTag(EndTagToken("caption"));
     if (!ignoreEndTag) {
       return token;
     }
@@ -2703,13 +2652,13 @@
     if (!ignoreEndTagCaption()) {
       // AT this code is quite similar to endTagTable in "InTable"
       tree.generateImpliedEndTags();
-      if (tree.openElements.last.localName != 'caption') {
-        parser.parseError(token.span, 'expected-one-end-tag-but-got-another', {
-          'gotName': 'caption',
-          'expectedName': tree.openElements.last.localName
+      if (tree.openElements.last.localName != "caption") {
+        parser.parseError(token.span, "expected-one-end-tag-but-got-another", {
+          "gotName": "caption",
+          "expectedName": tree.openElements.last.localName
         });
       }
-      while (tree.openElements.last.localName != 'caption') {
+      while (tree.openElements.last.localName != "caption") {
         tree.openElements.removeLast();
       }
       var node = tree.openElements.removeLast();
@@ -2719,14 +2668,14 @@
     } else {
       // innerHTML case
       assert(parser.innerHTMLMode);
-      parser.parseError(token.span, 'undefined-error');
+      parser.parseError(token.span, "undefined-error");
     }
   }
 
   Token endTagTable(EndTagToken token) {
-    parser.parseError(token.span, 'undefined-error');
+    parser.parseError(token.span, "undefined-error");
     var ignoreEndTag = ignoreEndTagCaption();
-    parser.phase.processEndTag(EndTagToken('caption'));
+    parser.phase.processEndTag(EndTagToken("caption"));
     if (!ignoreEndTag) {
       return token;
     }
@@ -2734,7 +2683,7 @@
   }
 
   void endTagIgnore(EndTagToken token) {
-    parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
   }
 
   Token endTagOther(EndTagToken token) {
@@ -2746,12 +2695,11 @@
   // http://www.whatwg.org/specs/web-apps/current-work///in-column
   InColumnGroupPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'col':
+      case "col":
         startTagCol(token);
         return null;
       default:
@@ -2759,13 +2707,12 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'colgroup':
+      case "colgroup":
         endTagColgroup(token);
         return null;
-      case 'col':
+      case "col":
         endTagCol(token);
         return null;
       default:
@@ -2774,25 +2721,23 @@
   }
 
   bool ignoreEndTagColgroup() {
-    return tree.openElements.last.localName == 'html';
+    return tree.openElements.last.localName == "html";
   }
 
-  @override
   bool processEOF() {
     var ignoreEndTag = ignoreEndTagColgroup();
     if (ignoreEndTag) {
       assert(parser.innerHTMLMode);
       return false;
     } else {
-      endTagColgroup(EndTagToken('colgroup'));
+      endTagColgroup(EndTagToken("colgroup"));
       return true;
     }
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     var ignoreEndTag = ignoreEndTagColgroup();
-    endTagColgroup(EndTagToken('colgroup'));
+    endTagColgroup(EndTagToken("colgroup"));
     return ignoreEndTag ? null : token;
   }
 
@@ -2803,7 +2748,7 @@
 
   Token startTagOther(StartTagToken token) {
     var ignoreEndTag = ignoreEndTagColgroup();
-    endTagColgroup(EndTagToken('colgroup'));
+    endTagColgroup(EndTagToken("colgroup"));
     return ignoreEndTag ? null : token;
   }
 
@@ -2811,7 +2756,7 @@
     if (ignoreEndTagColgroup()) {
       // innerHTML case
       assert(parser.innerHTMLMode);
-      parser.parseError(token.span, 'undefined-error');
+      parser.parseError(token.span, "undefined-error");
     } else {
       var node = tree.openElements.removeLast();
       node.endSourceSpan = token.span;
@@ -2820,12 +2765,12 @@
   }
 
   void endTagCol(EndTagToken token) {
-    parser.parseError(token.span, 'no-end-tag', {'name': 'col'});
+    parser.parseError(token.span, "no-end-tag", {"name": "col"});
   }
 
   Token endTagOther(EndTagToken token) {
     var ignoreEndTag = ignoreEndTagColgroup();
-    endTagColgroup(EndTagToken('colgroup'));
+    endTagColgroup(EndTagToken("colgroup"));
     return ignoreEndTag ? null : token;
   }
 }
@@ -2834,47 +2779,45 @@
   // http://www.whatwg.org/specs/web-apps/current-work///in-table0
   InTableBodyPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'tr':
+      case "tr":
         startTagTr(token);
         return null;
-      case 'td':
-      case 'th':
+      case "td":
+      case "th":
         return startTagTableCell(token);
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
+      case "caption":
+      case "col":
+      case "colgroup":
+      case "tbody":
+      case "tfoot":
+      case "thead":
         return startTagTableOther(token);
       default:
         return startTagOther(token);
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
+      case "tbody":
+      case "tfoot":
+      case "thead":
         endTagTableRowGroup(token);
         return null;
-      case 'table':
+      case "table":
         return endTagTable(token);
-      case 'body':
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'html':
-      case 'td':
-      case 'th':
-      case 'tr':
+      case "body":
+      case "caption":
+      case "col":
+      case "colgroup":
+      case "html":
+      case "td":
+      case "th":
+      case "tr":
         endTagIgnore(token);
         return null;
       default:
@@ -2884,30 +2827,27 @@
 
   // helper methods
   void clearStackToTableBodyContext() {
-    var tableTags = const ['tbody', 'tfoot', 'thead', 'html'];
+    var tableTags = const ["tbody", "tfoot", "thead", "html"];
     while (!tableTags.contains(tree.openElements.last.localName)) {
       //XXX parser.parseError(token.span, "unexpected-implied-end-tag-in-table",
       //  {"name": tree.openElements.last.name})
       tree.openElements.removeLast();
     }
-    if (tree.openElements.last.localName == 'html') {
+    if (tree.openElements.last.localName == "html") {
       assert(parser.innerHTMLMode);
     }
   }
 
   // the rest
-  @override
   bool processEOF() {
     parser._inTablePhase.processEOF();
     return false;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     return parser._inTablePhase.processSpaceCharacters(token);
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     return parser._inTablePhase.processCharacters(token);
   }
@@ -2920,8 +2860,8 @@
 
   Token startTagTableCell(StartTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-cell-in-table-body', {'name': token.name});
-    startTagTr(StartTagToken('tr', data: LinkedHashMap<dynamic, String>()));
+        token.span, "unexpected-cell-in-table-body", {"name": token.name});
+    startTagTr(StartTagToken("tr", data: LinkedHashMap<dynamic, String>()));
     return token;
   }
 
@@ -2932,36 +2872,36 @@
   }
 
   void endTagTableRowGroup(EndTagToken token) {
-    if (tree.elementInScope(token.name, variant: 'table')) {
+    if (tree.elementInScope(token.name, variant: "table")) {
       clearStackToTableBodyContext();
       var node = tree.openElements.removeLast();
       node.endSourceSpan = token.span;
       parser.phase = parser._inTablePhase;
     } else {
       parser.parseError(
-          token.span, 'unexpected-end-tag-in-table-body', {'name': token.name});
+          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')) {
+    if (tree.elementInScope("tbody", variant: "table") ||
+        tree.elementInScope("thead", variant: "table") ||
+        tree.elementInScope("tfoot", variant: "table")) {
       clearStackToTableBodyContext();
       endTagTableRowGroup(EndTagToken(tree.openElements.last.localName));
       return token;
     } else {
       // innerHTML case
       assert(parser.innerHTMLMode);
-      parser.parseError(token.span, 'undefined-error');
+      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.span, "unexpected-end-tag-in-table-body", {"name": token.name});
   }
 
   Token endTagOther(EndTagToken token) {
@@ -2973,47 +2913,45 @@
   // http://www.whatwg.org/specs/web-apps/current-work///in-row
   InRowPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'td':
-      case 'th':
+      case "td":
+      case "th":
         startTagTableCell(token);
         return null;
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
-      case 'tr':
+      case "caption":
+      case "col":
+      case "colgroup":
+      case "tbody":
+      case "tfoot":
+      case "thead":
+      case "tr":
         return startTagTableOther(token);
       default:
         return startTagOther(token);
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'tr':
+      case "tr":
         endTagTr(token);
         return null;
-      case 'table':
+      case "table":
         return endTagTable(token);
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
+      case "tbody":
+      case "tfoot":
+      case "thead":
         return endTagTableRowGroup(token);
-      case 'body':
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'html':
-      case 'td':
-      case 'th':
+      case "body":
+      case "caption":
+      case "col":
+      case "colgroup":
+      case "html":
+      case "td":
+      case "th":
         endTagIgnore(token);
         return null;
       default:
@@ -3025,33 +2963,30 @@
   void clearStackToTableRowContext() {
     while (true) {
       var last = tree.openElements.last;
-      if (last.localName == 'tr' || last.localName == 'html') break;
+      if (last.localName == "tr" || last.localName == "html") break;
 
       parser.parseError(
           last.sourceSpan,
-          'unexpected-implied-end-tag-in-table-row',
-          {'name': tree.openElements.last.localName});
+          "unexpected-implied-end-tag-in-table-row",
+          {"name": tree.openElements.last.localName});
       tree.openElements.removeLast();
     }
   }
 
   bool ignoreEndTagTr() {
-    return !tree.elementInScope('tr', variant: 'table');
+    return !tree.elementInScope("tr", variant: "table");
   }
 
   // the rest
-  @override
   bool processEOF() {
     parser._inTablePhase.processEOF();
     return false;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     return parser._inTablePhase.processSpaceCharacters(token);
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     return parser._inTablePhase.processCharacters(token);
   }
@@ -3064,8 +2999,8 @@
   }
 
   Token startTagTableOther(StartTagToken token) {
-    var ignoreEndTag = ignoreEndTagTr();
-    endTagTr(EndTagToken('tr'));
+    bool ignoreEndTag = ignoreEndTagTr();
+    endTagTr(EndTagToken("tr"));
     // XXX how are we sure it's always ignored in the innerHTML case?
     return ignoreEndTag ? null : token;
   }
@@ -3083,31 +3018,31 @@
     } else {
       // innerHTML case
       assert(parser.innerHTMLMode);
-      parser.parseError(token.span, 'undefined-error');
+      parser.parseError(token.span, "undefined-error");
     }
   }
 
   Token endTagTable(EndTagToken token) {
     var ignoreEndTag = ignoreEndTagTr();
-    endTagTr(EndTagToken('tr'));
+    endTagTr(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(EndTagToken('tr'));
+    if (tree.elementInScope(token.name, variant: "table")) {
+      endTagTr(EndTagToken("tr"));
       return token;
     } else {
-      parser.parseError(token.span, 'undefined-error');
+      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.span, "unexpected-end-tag-in-table-row", {"name": token.name});
   }
 
   Token endTagOther(EndTagToken token) {
@@ -3119,45 +3054,43 @@
   // http://www.whatwg.org/specs/web-apps/current-work///in-cell
   InCellPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'tbody':
-      case 'td':
-      case 'tfoot':
-      case 'th':
-      case 'thead':
-      case 'tr':
+      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);
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'td':
-      case 'th':
+      case "td":
+      case "th":
         endTagTableCell(token);
         return null;
-      case 'body':
-      case 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'html':
+      case "body":
+      case "caption":
+      case "col":
+      case "colgroup":
+      case "html":
         endTagIgnore(token);
         return null;
-      case 'table':
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
-      case 'tr':
+      case "table":
+      case "tbody":
+      case "tfoot":
+      case "thead":
+      case "tr":
         return endTagImply(token);
       default:
         return endTagOther(token);
@@ -3166,34 +3099,32 @@
 
   // helper
   void closeCell() {
-    if (tree.elementInScope('td', variant: 'table')) {
-      endTagTableCell(EndTagToken('td'));
-    } else if (tree.elementInScope('th', variant: 'table')) {
-      endTagTableCell(EndTagToken('th'));
+    if (tree.elementInScope("td", variant: "table")) {
+      endTagTableCell(EndTagToken("td"));
+    } else if (tree.elementInScope("th", variant: "table")) {
+      endTagTableCell(EndTagToken("th"));
     }
   }
 
   // the rest
-  @override
   bool processEOF() {
     parser._inBodyPhase.processEOF();
     return false;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     return parser._inBodyPhase.processCharacters(token);
   }
 
   Token startTagTableOther(StartTagToken token) {
-    if (tree.elementInScope('td', variant: 'table') ||
-        tree.elementInScope('th', variant: 'table')) {
+    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');
+      parser.parseError(token.span, "undefined-error");
       return null;
     }
   }
@@ -3203,11 +3134,11 @@
   }
 
   void endTagTableCell(EndTagToken token) {
-    if (tree.elementInScope(token.name, variant: 'table')) {
+    if (tree.elementInScope(token.name, variant: "table")) {
       tree.generateImpliedEndTags(token.name);
       if (tree.openElements.last.localName != token.name) {
         parser.parseError(
-            token.span, 'unexpected-cell-end-tag', {'name': token.name});
+            token.span, "unexpected-cell-end-tag", {"name": token.name});
         popOpenElementsUntil(token);
       } else {
         var node = tree.openElements.removeLast();
@@ -3216,21 +3147,21 @@
       tree.clearActiveFormattingElements();
       parser.phase = parser._inRowPhase;
     } else {
-      parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+      parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
     }
   }
 
   void endTagIgnore(EndTagToken token) {
-    parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+    parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
   }
 
   Token endTagImply(EndTagToken token) {
-    if (tree.elementInScope(token.name, variant: 'table')) {
+    if (tree.elementInScope(token.name, variant: "table")) {
       closeCell();
       return token;
     } else {
       // sometimes innerHTML case
-      parser.parseError(token.span, 'undefined-error');
+      parser.parseError(token.span, "undefined-error");
     }
     return null;
   }
@@ -3243,41 +3174,39 @@
 class InSelectPhase extends Phase {
   InSelectPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'option':
+      case "option":
         startTagOption(token);
         return null;
-      case 'optgroup':
+      case "optgroup":
         startTagOptgroup(token);
         return null;
-      case 'select':
+      case "select":
         startTagSelect(token);
         return null;
-      case 'input':
-      case 'keygen':
-      case 'textarea':
+      case "input":
+      case "keygen":
+      case "textarea":
         return startTagInput(token);
-      case 'script':
+      case "script":
         return startTagScript(token);
       default:
         return startTagOther(token);
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'option':
+      case "option":
         endTagOption(token);
         return null;
-      case 'optgroup':
+      case "optgroup":
         endTagOptgroup(token);
         return null;
-      case 'select':
+      case "select":
         endTagSelect(token);
         return null;
       default:
@@ -3287,20 +3216,18 @@
   }
 
   // http://www.whatwg.org/specs/web-apps/current-work///in-select
-  @override
   bool processEOF() {
     var last = tree.openElements.last;
-    if (last.localName != 'html') {
-      parser.parseError(last.sourceSpan, 'eof-in-select');
+    if (last.localName != "html") {
+      parser.parseError(last.sourceSpan, "eof-in-select");
     } else {
       assert(parser.innerHTMLMode);
     }
     return false;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    if (token.data == '\u0000') {
+    if (token.data == "\u0000") {
       return null;
     }
     tree.insertText(token.data, token.span);
@@ -3309,31 +3236,31 @@
 
   void startTagOption(StartTagToken token) {
     // We need to imply </option> if <option> is the current node.
-    if (tree.openElements.last.localName == 'option') {
+    if (tree.openElements.last.localName == "option") {
       tree.openElements.removeLast();
     }
     tree.insertElement(token);
   }
 
   void startTagOptgroup(StartTagToken token) {
-    if (tree.openElements.last.localName == 'option') {
+    if (tree.openElements.last.localName == "option") {
       tree.openElements.removeLast();
     }
-    if (tree.openElements.last.localName == 'optgroup') {
+    if (tree.openElements.last.localName == "optgroup") {
       tree.openElements.removeLast();
     }
     tree.insertElement(token);
   }
 
   void startTagSelect(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-select-in-select');
-    endTagSelect(EndTagToken('select'));
+    parser.parseError(token.span, "unexpected-select-in-select");
+    endTagSelect(EndTagToken("select"));
   }
 
   Token startTagInput(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-input-in-select');
-    if (tree.elementInScope('select', variant: 'select')) {
-      endTagSelect(EndTagToken('select'));
+    parser.parseError(token.span, "unexpected-input-in-select");
+    if (tree.elementInScope("select", variant: "select")) {
+      endTagSelect(EndTagToken("select"));
       return token;
     } else {
       assert(parser.innerHTMLMode);
@@ -3347,99 +3274,95 @@
 
   Token startTagOther(StartTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-start-tag-in-select', {'name': token.name});
+        token.span, "unexpected-start-tag-in-select", {"name": token.name});
     return null;
   }
 
   void endTagOption(EndTagToken token) {
-    if (tree.openElements.last.localName == 'option') {
+    if (tree.openElements.last.localName == "option") {
       var node = tree.openElements.removeLast();
       node.endSourceSpan = token.span;
     } else {
       parser.parseError(
-          token.span, 'unexpected-end-tag-in-select', {'name': 'option'});
+          token.span, "unexpected-end-tag-in-select", {"name": "option"});
     }
   }
 
   void endTagOptgroup(EndTagToken token) {
     // </optgroup> implicitly closes <option>
-    if (tree.openElements.last.localName == 'option' &&
+    if (tree.openElements.last.localName == "option" &&
         tree.openElements[tree.openElements.length - 2].localName ==
-            'optgroup') {
+            "optgroup") {
       tree.openElements.removeLast();
     }
     // It also closes </optgroup>
-    if (tree.openElements.last.localName == 'optgroup') {
+    if (tree.openElements.last.localName == "optgroup") {
       var node = tree.openElements.removeLast();
       node.endSourceSpan = token.span;
       // But nothing else
     } else {
       parser.parseError(
-          token.span, 'unexpected-end-tag-in-select', {'name': 'optgroup'});
+          token.span, "unexpected-end-tag-in-select", {"name": "optgroup"});
     }
   }
 
   void endTagSelect(EndTagToken token) {
-    if (tree.elementInScope('select', variant: 'select')) {
+    if (tree.elementInScope("select", variant: "select")) {
       popOpenElementsUntil(token);
       parser.resetInsertionMode();
     } else {
       // innerHTML case
       assert(parser.innerHTMLMode);
-      parser.parseError(token.span, 'undefined-error');
+      parser.parseError(token.span, "undefined-error");
     }
   }
 
   void endTagOther(EndTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-end-tag-in-select', {'name': token.name});
+        token.span, "unexpected-end-tag-in-select", {"name": token.name});
   }
 }
 
 class InSelectInTablePhase extends Phase {
   InSelectInTablePhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'caption':
-      case 'table':
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
-      case 'tr':
-      case 'td':
-      case 'th':
+      case "caption":
+      case "table":
+      case "tbody":
+      case "tfoot":
+      case "thead":
+      case "tr":
+      case "td":
+      case "th":
         return startTagTable(token);
       default:
         return startTagOther(token);
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'caption':
-      case 'table':
-      case 'tbody':
-      case 'tfoot':
-      case 'thead':
-      case 'tr':
-      case 'td':
-      case 'th':
+      case "caption":
+      case "table":
+      case "tbody":
+      case "tfoot":
+      case "thead":
+      case "tr":
+      case "td":
+      case "th":
         return endTagTable(token);
       default:
         return endTagOther(token);
     }
   }
 
-  @override
   bool processEOF() {
     parser._inSelectPhase.processEOF();
     return false;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
     return parser._inSelectPhase.processCharacters(token);
   }
@@ -3447,9 +3370,9 @@
   Token startTagTable(StartTagToken token) {
     parser.parseError(
         token.span,
-        'unexpected-table-element-start-tag-in-select-in-table',
-        {'name': token.name});
-    endTagOther(EndTagToken('select'));
+        "unexpected-table-element-start-tag-in-select-in-table",
+        {"name": token.name});
+    endTagOther(EndTagToken("select"));
     return token;
   }
 
@@ -3460,10 +3383,10 @@
   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(EndTagToken('select'));
+        "unexpected-table-element-end-tag-in-select-in-table",
+        {"name": token.name});
+    if (tree.elementInScope(token.name, variant: "table")) {
+      endTagOther(EndTagToken("select"));
       return token;
     }
     return null;
@@ -3527,42 +3450,42 @@
 
   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'
+      "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];
@@ -3571,26 +3494,24 @@
     }
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    if (token.data == '\u0000') {
-      token.replaceData('\uFFFD');
+    if (token.data == "\u0000") {
+      token.replaceData("\uFFFD");
     } else if (parser.framesetOK && !allWhitespace(token.data)) {
       parser.framesetOK = false;
     }
     return super.processCharacters(token);
   }
 
-  @override
   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')))) {
+        (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});
+          "unexpected-html-element-in-foreign-content", {'name': token.name});
       while (tree.openElements.last.namespaceUri != tree.defaultNamespace &&
           !parser.isHTMLIntegrationPoint(tree.openElements.last) &&
           !parser.isMathMLTextIntegrationPoint(tree.openElements.last)) {
@@ -3615,12 +3536,11 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     var nodeIndex = tree.openElements.length - 1;
     var node = tree.openElements.last;
     if (asciiUpper2Lower(node.localName) != token.name) {
-      parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+      parser.parseError(token.span, "unexpected-end-tag", {"name": token.name});
     }
 
     Token newToken;
@@ -3655,15 +3575,13 @@
 class AfterBodyPhase extends Phase {
   AfterBodyPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
-    if (token.name == 'html') return startTagHtml(token);
+    if (token.name == "html") return startTagHtml(token);
     return startTagOther(token);
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
-    if (token.name == 'html') {
+    if (token.name == "html") {
       endTagHtml(token);
       return null;
     }
@@ -3671,10 +3589,8 @@
   }
 
   //Stop parsing
-  @override
   bool processEOF() => false;
 
-  @override
   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.
@@ -3682,21 +3598,19 @@
     return null;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    parser.parseError(token.span, 'unexpected-char-after-body');
+    parser.parseError(token.span, "unexpected-char-after-body");
     parser.phase = parser._inBodyPhase;
     return token;
   }
 
-  @override
   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});
+        token.span, "unexpected-start-tag-after-body", {"name": token.name});
     parser.phase = parser._inBodyPhase;
     return token;
   }
@@ -3709,7 +3623,7 @@
       }
     }
     if (parser.innerHTMLMode) {
-      parser.parseError(token.span, 'unexpected-end-tag-after-body-innerhtml');
+      parser.parseError(token.span, "unexpected-end-tag-after-body-innerhtml");
     } else {
       parser.phase = parser._afterAfterBodyPhase;
     }
@@ -3717,7 +3631,7 @@
 
   Token endTagOther(EndTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-end-tag-after-body', {'name': token.name});
+        token.span, "unexpected-end-tag-after-body", {"name": token.name});
     parser.phase = parser._inBodyPhase;
     return token;
   }
@@ -3727,28 +3641,26 @@
   // http://www.whatwg.org/specs/web-apps/current-work///in-frameset
   InFramesetPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'frameset':
+      case "frameset":
         startTagFrameset(token);
         return null;
-      case 'frame':
+      case "frame":
         startTagFrame(token);
         return null;
-      case 'noframes':
+      case "noframes":
         return startTagNoframes(token);
       default:
         return startTagOther(token);
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'frameset':
+      case "frameset":
         endTagFrameset(token);
         return null;
       default:
@@ -3757,20 +3669,18 @@
     }
   }
 
-  @override
   bool processEOF() {
     var last = tree.openElements.last;
-    if (last.localName != 'html') {
-      parser.parseError(last.sourceSpan, 'eof-in-frameset');
+    if (last.localName != "html") {
+      parser.parseError(last.sourceSpan, "eof-in-frameset");
     } else {
       assert(parser.innerHTMLMode);
     }
     return false;
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    parser.parseError(token.span, 'unexpected-char-in-frameset');
+    parser.parseError(token.span, "unexpected-char-in-frameset");
     return null;
   }
 
@@ -3789,21 +3699,21 @@
 
   Token startTagOther(StartTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-start-tag-in-frameset', {'name': token.name});
+        token.span, "unexpected-start-tag-in-frameset", {"name": token.name});
     return null;
   }
 
   void endTagFrameset(EndTagToken token) {
-    if (tree.openElements.last.localName == 'html') {
+    if (tree.openElements.last.localName == "html") {
       // innerHTML case
       parser.parseError(
-          token.span, 'unexpected-frameset-in-frameset-innerhtml');
+          token.span, "unexpected-frameset-in-frameset-innerhtml");
     } else {
       var node = tree.openElements.removeLast();
       node.endSourceSpan = token.span;
     }
     if (!parser.innerHTMLMode &&
-        tree.openElements.last.localName != 'frameset') {
+        tree.openElements.last.localName != "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;
@@ -3812,7 +3722,7 @@
 
   void endTagOther(EndTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-end-tag-in-frameset', {'name': token.name});
+        token.span, "unexpected-end-tag-in-frameset", {"name": token.name});
   }
 }
 
@@ -3820,12 +3730,11 @@
   // http://www.whatwg.org/specs/web-apps/current-work///after3
   AfterFramesetPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'noframes':
+      case "noframes":
         return startTagNoframes(token);
       default:
         startTagOther(token);
@@ -3833,10 +3742,9 @@
     }
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         endTagHtml(token);
         return null;
       default:
@@ -3846,12 +3754,10 @@
   }
 
   // Stop parsing
-  @override
   bool processEOF() => false;
 
-  @override
   Token processCharacters(CharactersToken token) {
-    parser.parseError(token.span, 'unexpected-char-after-frameset');
+    parser.parseError(token.span, "unexpected-char-after-frameset");
     return null;
   }
 
@@ -3860,8 +3766,8 @@
   }
 
   void startTagOther(StartTagToken token) {
-    parser.parseError(token.span, 'unexpected-start-tag-after-frameset',
-        {'name': token.name});
+    parser.parseError(token.span, "unexpected-start-tag-after-frameset",
+        {"name": token.name});
   }
 
   void endTagHtml(EndTagToken token) {
@@ -3870,56 +3776,49 @@
 
   void endTagOther(EndTagToken token) {
     parser.parseError(
-        token.span, 'unexpected-end-tag-after-frameset', {'name': token.name});
+        token.span, "unexpected-end-tag-after-frameset", {"name": token.name});
   }
 }
 
 class AfterAfterBodyPhase extends Phase {
   AfterAfterBodyPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     if (token.name == 'html') return startTagHtml(token);
     return startTagOther(token);
   }
 
-  @override
   bool processEOF() => false;
 
-  @override
   Token processComment(CommentToken token) {
     tree.insertComment(token, tree.document);
     return null;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     return parser._inBodyPhase.processSpaceCharacters(token);
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    parser.parseError(token.span, 'expected-eof-but-got-char');
+    parser.parseError(token.span, "expected-eof-but-got-char");
     parser.phase = parser._inBodyPhase;
     return token;
   }
 
-  @override
   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});
+        token.span, "expected-eof-but-got-start-tag", {"name": token.name});
     parser.phase = parser._inBodyPhase;
     return token;
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     parser.parseError(
-        token.span, 'expected-eof-but-got-end-tag', {'name': token.name});
+        token.span, "expected-eof-but-got-end-tag", {"name": token.name});
     parser.phase = parser._inBodyPhase;
     return token;
   }
@@ -3928,12 +3827,11 @@
 class AfterAfterFramesetPhase extends Phase {
   AfterAfterFramesetPhase(parser) : super(parser);
 
-  @override
   Token processStartTag(StartTagToken token) {
     switch (token.name) {
-      case 'html':
+      case "html":
         return startTagHtml(token);
-      case 'noframes':
+      case "noframes":
         return startTagNoFrames(token);
       default:
         startTagOther(token);
@@ -3941,27 +3839,22 @@
     }
   }
 
-  @override
   bool processEOF() => false;
 
-  @override
   Token processComment(CommentToken token) {
     tree.insertComment(token, tree.document);
     return null;
   }
 
-  @override
   Token processSpaceCharacters(SpaceCharactersToken token) {
     return parser._inBodyPhase.processSpaceCharacters(token);
   }
 
-  @override
   Token processCharacters(CharactersToken token) {
-    parser.parseError(token.span, 'expected-eof-but-got-char');
+    parser.parseError(token.span, "expected-eof-but-got-char");
     return null;
   }
 
-  @override
   Token startTagHtml(StartTagToken token) {
     return parser._inBodyPhase.processStartTag(token);
   }
@@ -3972,13 +3865,12 @@
 
   void startTagOther(StartTagToken token) {
     parser.parseError(
-        token.span, 'expected-eof-but-got-start-tag', {'name': token.name});
+        token.span, "expected-eof-but-got-start-tag", {"name": token.name});
   }
 
-  @override
   Token processEndTag(EndTagToken token) {
     parser.parseError(
-        token.span, 'expected-eof-but-got-end-tag', {'name': token.name});
+        token.span, "expected-eof-but-got-end-tag", {"name": token.name});
     return null;
   }
 }
@@ -3986,7 +3878,6 @@
 /// Error in parsed document.
 class ParseError implements SourceSpanException {
   final String errorCode;
-  @override
   final SourceSpan span;
   final Map data;
 
@@ -4002,10 +3893,8 @@
   /// [span.getLocationMessage] and [toString] are equivalent. Otherwise,
   /// [span.getLocationMessage] will not show any source url information, but
   /// [toString] will include 'ParserError:' as a prefix.
-  @override
   String get message => formatStr(errorMessages[errorCode], data);
 
-  @override
   String toString({color}) {
     var res = span.message(message, color: color);
     return span.sourceUrl == null ? 'ParserError on $res' : 'On $res';
@@ -4014,6 +3903,7 @@
 
 /// Convenience function to get the pair of namespace and localName.
 Pair<String, String> getElementNameTuple(Element e) {
-  var ns = e.namespaceUri ?? Namespaces.html;
+  var ns = e.namespaceUri;
+  if (ns == null) ns = Namespaces.html;
   return Pair(ns, e.localName);
 }
diff --git a/html/lib/src/constants.dart b/html/lib/src/constants.dart
index 313b952..34addfc 100644
--- a/html/lib/src/constants.dart
+++ b/html/lib/src/constants.dart
@@ -1,3 +1,5 @@
+library constants;
+
 import 'utils.dart';
 
 // TODO(jmesserly): fix up the const lists. For the bigger ones, we need faster
@@ -9,8 +11,7 @@
 class ReparseException implements Exception {
   final String message;
   ReparseException(this.message);
-  @override
-  String toString() => 'ReparseException: $message';
+  String toString() => "ReparseException: $message";
 }
 
 // TODO(jmesserly): assuming the programmatic name is not important, it would be
@@ -19,228 +20,228 @@
 /// style string formatting, as implemented by [formatStr]. That function only
 /// supports the subset of format functionality used here.
 const Map<String, String> errorMessages = {
-  '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':
+  "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.',
+          "(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':
+      "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-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':
+          "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-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':
+  "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',
+  '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 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':
+  "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':
+  "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)',
+  "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/';
+  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) {
@@ -264,141 +265,141 @@
 }
 
 const List scopingElements = [
-  Pair(Namespaces.html, 'applet'),
-  Pair(Namespaces.html, 'caption'),
-  Pair(Namespaces.html, 'html'),
-  Pair(Namespaces.html, 'marquee'),
-  Pair(Namespaces.html, 'object'),
-  Pair(Namespaces.html, 'table'),
-  Pair(Namespaces.html, 'td'),
-  Pair(Namespaces.html, 'th'),
-  Pair(Namespaces.mathml, 'mi'),
-  Pair(Namespaces.mathml, 'mo'),
-  Pair(Namespaces.mathml, 'mn'),
-  Pair(Namespaces.mathml, 'ms'),
-  Pair(Namespaces.mathml, 'mtext'),
-  Pair(Namespaces.mathml, 'annotation-xml'),
-  Pair(Namespaces.svg, 'foreignObject'),
-  Pair(Namespaces.svg, 'desc'),
-  Pair(Namespaces.svg, 'title')
+  Pair(Namespaces.html, "applet"),
+  Pair(Namespaces.html, "caption"),
+  Pair(Namespaces.html, "html"),
+  Pair(Namespaces.html, "marquee"),
+  Pair(Namespaces.html, "object"),
+  Pair(Namespaces.html, "table"),
+  Pair(Namespaces.html, "td"),
+  Pair(Namespaces.html, "th"),
+  Pair(Namespaces.mathml, "mi"),
+  Pair(Namespaces.mathml, "mo"),
+  Pair(Namespaces.mathml, "mn"),
+  Pair(Namespaces.mathml, "ms"),
+  Pair(Namespaces.mathml, "mtext"),
+  Pair(Namespaces.mathml, "annotation-xml"),
+  Pair(Namespaces.svg, "foreignObject"),
+  Pair(Namespaces.svg, "desc"),
+  Pair(Namespaces.svg, "title")
 ];
 
 const formattingElements = [
-  Pair(Namespaces.html, 'a'),
-  Pair(Namespaces.html, 'b'),
-  Pair(Namespaces.html, 'big'),
-  Pair(Namespaces.html, 'code'),
-  Pair(Namespaces.html, 'em'),
-  Pair(Namespaces.html, 'font'),
-  Pair(Namespaces.html, 'i'),
-  Pair(Namespaces.html, 'nobr'),
-  Pair(Namespaces.html, 's'),
-  Pair(Namespaces.html, 'small'),
-  Pair(Namespaces.html, 'strike'),
-  Pair(Namespaces.html, 'strong'),
-  Pair(Namespaces.html, 'tt'),
-  Pair(Namespaces.html, '')
+  Pair(Namespaces.html, "a"),
+  Pair(Namespaces.html, "b"),
+  Pair(Namespaces.html, "big"),
+  Pair(Namespaces.html, "code"),
+  Pair(Namespaces.html, "em"),
+  Pair(Namespaces.html, "font"),
+  Pair(Namespaces.html, "i"),
+  Pair(Namespaces.html, "nobr"),
+  Pair(Namespaces.html, "s"),
+  Pair(Namespaces.html, "small"),
+  Pair(Namespaces.html, "strike"),
+  Pair(Namespaces.html, "strong"),
+  Pair(Namespaces.html, "tt"),
+  Pair(Namespaces.html, "")
 ];
 
 const specialElements = [
-  Pair(Namespaces.html, 'address'),
-  Pair(Namespaces.html, 'applet'),
-  Pair(Namespaces.html, 'area'),
-  Pair(Namespaces.html, 'article'),
-  Pair(Namespaces.html, 'aside'),
-  Pair(Namespaces.html, 'base'),
-  Pair(Namespaces.html, 'basefont'),
-  Pair(Namespaces.html, 'bgsound'),
-  Pair(Namespaces.html, 'blockquote'),
-  Pair(Namespaces.html, 'body'),
-  Pair(Namespaces.html, 'br'),
-  Pair(Namespaces.html, 'button'),
-  Pair(Namespaces.html, 'caption'),
-  Pair(Namespaces.html, 'center'),
-  Pair(Namespaces.html, 'col'),
-  Pair(Namespaces.html, 'colgroup'),
-  Pair(Namespaces.html, 'command'),
-  Pair(Namespaces.html, 'dd'),
-  Pair(Namespaces.html, 'details'),
-  Pair(Namespaces.html, 'dir'),
-  Pair(Namespaces.html, 'div'),
-  Pair(Namespaces.html, 'dl'),
-  Pair(Namespaces.html, 'dt'),
-  Pair(Namespaces.html, 'embed'),
-  Pair(Namespaces.html, 'fieldset'),
-  Pair(Namespaces.html, 'figure'),
-  Pair(Namespaces.html, 'footer'),
-  Pair(Namespaces.html, 'form'),
-  Pair(Namespaces.html, 'frame'),
-  Pair(Namespaces.html, 'frameset'),
-  Pair(Namespaces.html, 'h1'),
-  Pair(Namespaces.html, 'h2'),
-  Pair(Namespaces.html, 'h3'),
-  Pair(Namespaces.html, 'h4'),
-  Pair(Namespaces.html, 'h5'),
-  Pair(Namespaces.html, 'h6'),
-  Pair(Namespaces.html, 'head'),
-  Pair(Namespaces.html, 'header'),
-  Pair(Namespaces.html, 'hr'),
-  Pair(Namespaces.html, 'html'),
-  Pair(Namespaces.html, 'iframe'),
+  Pair(Namespaces.html, "address"),
+  Pair(Namespaces.html, "applet"),
+  Pair(Namespaces.html, "area"),
+  Pair(Namespaces.html, "article"),
+  Pair(Namespaces.html, "aside"),
+  Pair(Namespaces.html, "base"),
+  Pair(Namespaces.html, "basefont"),
+  Pair(Namespaces.html, "bgsound"),
+  Pair(Namespaces.html, "blockquote"),
+  Pair(Namespaces.html, "body"),
+  Pair(Namespaces.html, "br"),
+  Pair(Namespaces.html, "button"),
+  Pair(Namespaces.html, "caption"),
+  Pair(Namespaces.html, "center"),
+  Pair(Namespaces.html, "col"),
+  Pair(Namespaces.html, "colgroup"),
+  Pair(Namespaces.html, "command"),
+  Pair(Namespaces.html, "dd"),
+  Pair(Namespaces.html, "details"),
+  Pair(Namespaces.html, "dir"),
+  Pair(Namespaces.html, "div"),
+  Pair(Namespaces.html, "dl"),
+  Pair(Namespaces.html, "dt"),
+  Pair(Namespaces.html, "embed"),
+  Pair(Namespaces.html, "fieldset"),
+  Pair(Namespaces.html, "figure"),
+  Pair(Namespaces.html, "footer"),
+  Pair(Namespaces.html, "form"),
+  Pair(Namespaces.html, "frame"),
+  Pair(Namespaces.html, "frameset"),
+  Pair(Namespaces.html, "h1"),
+  Pair(Namespaces.html, "h2"),
+  Pair(Namespaces.html, "h3"),
+  Pair(Namespaces.html, "h4"),
+  Pair(Namespaces.html, "h5"),
+  Pair(Namespaces.html, "h6"),
+  Pair(Namespaces.html, "head"),
+  Pair(Namespaces.html, "header"),
+  Pair(Namespaces.html, "hr"),
+  Pair(Namespaces.html, "html"),
+  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,"
-  Pair(Namespaces.html, 'image'),
-  Pair(Namespaces.html, 'img'),
-  Pair(Namespaces.html, 'input'),
-  Pair(Namespaces.html, 'isindex'),
-  Pair(Namespaces.html, 'li'),
-  Pair(Namespaces.html, 'link'),
-  Pair(Namespaces.html, 'listing'),
-  Pair(Namespaces.html, 'marquee'),
-  Pair(Namespaces.html, 'men'),
-  Pair(Namespaces.html, 'meta'),
-  Pair(Namespaces.html, 'nav'),
-  Pair(Namespaces.html, 'noembed'),
-  Pair(Namespaces.html, 'noframes'),
-  Pair(Namespaces.html, 'noscript'),
-  Pair(Namespaces.html, 'object'),
-  Pair(Namespaces.html, 'ol'),
-  Pair(Namespaces.html, 'p'),
-  Pair(Namespaces.html, 'param'),
-  Pair(Namespaces.html, 'plaintext'),
-  Pair(Namespaces.html, 'pre'),
-  Pair(Namespaces.html, 'script'),
-  Pair(Namespaces.html, 'section'),
-  Pair(Namespaces.html, 'select'),
-  Pair(Namespaces.html, 'style'),
-  Pair(Namespaces.html, 'table'),
-  Pair(Namespaces.html, 'tbody'),
-  Pair(Namespaces.html, 'td'),
-  Pair(Namespaces.html, 'textarea'),
-  Pair(Namespaces.html, 'tfoot'),
-  Pair(Namespaces.html, 'th'),
-  Pair(Namespaces.html, 'thead'),
-  Pair(Namespaces.html, 'title'),
-  Pair(Namespaces.html, 'tr'),
-  Pair(Namespaces.html, 'ul'),
-  Pair(Namespaces.html, 'wbr'),
-  Pair(Namespaces.html, 'xmp'),
-  Pair(Namespaces.svg, 'foreignObject')
+  Pair(Namespaces.html, "image"),
+  Pair(Namespaces.html, "img"),
+  Pair(Namespaces.html, "input"),
+  Pair(Namespaces.html, "isindex"),
+  Pair(Namespaces.html, "li"),
+  Pair(Namespaces.html, "link"),
+  Pair(Namespaces.html, "listing"),
+  Pair(Namespaces.html, "marquee"),
+  Pair(Namespaces.html, "men"),
+  Pair(Namespaces.html, "meta"),
+  Pair(Namespaces.html, "nav"),
+  Pair(Namespaces.html, "noembed"),
+  Pair(Namespaces.html, "noframes"),
+  Pair(Namespaces.html, "noscript"),
+  Pair(Namespaces.html, "object"),
+  Pair(Namespaces.html, "ol"),
+  Pair(Namespaces.html, "p"),
+  Pair(Namespaces.html, "param"),
+  Pair(Namespaces.html, "plaintext"),
+  Pair(Namespaces.html, "pre"),
+  Pair(Namespaces.html, "script"),
+  Pair(Namespaces.html, "section"),
+  Pair(Namespaces.html, "select"),
+  Pair(Namespaces.html, "style"),
+  Pair(Namespaces.html, "table"),
+  Pair(Namespaces.html, "tbody"),
+  Pair(Namespaces.html, "td"),
+  Pair(Namespaces.html, "textarea"),
+  Pair(Namespaces.html, "tfoot"),
+  Pair(Namespaces.html, "th"),
+  Pair(Namespaces.html, "thead"),
+  Pair(Namespaces.html, "title"),
+  Pair(Namespaces.html, "tr"),
+  Pair(Namespaces.html, "ul"),
+  Pair(Namespaces.html, "wbr"),
+  Pair(Namespaces.html, "xmp"),
+  Pair(Namespaces.svg, "foreignObject")
 ];
 
 const htmlIntegrationPointElements = [
-  Pair(Namespaces.mathml, 'annotaion-xml'),
-  Pair(Namespaces.svg, 'foreignObject'),
-  Pair(Namespaces.svg, 'desc'),
-  Pair(Namespaces.svg, 'title')
+  Pair(Namespaces.mathml, "annotaion-xml"),
+  Pair(Namespaces.svg, "foreignObject"),
+  Pair(Namespaces.svg, "desc"),
+  Pair(Namespaces.svg, "title")
 ];
 
 const mathmlTextIntegrationPointElements = [
-  Pair(Namespaces.mathml, 'mi'),
-  Pair(Namespaces.mathml, 'mo'),
-  Pair(Namespaces.mathml, 'mn'),
-  Pair(Namespaces.mathml, 'ms'),
-  Pair(Namespaces.mathml, 'mtext')
+  Pair(Namespaces.mathml, "mi"),
+  Pair(Namespaces.mathml, "mo"),
+  Pair(Namespaces.mathml, "mn"),
+  Pair(Namespaces.mathml, "ms"),
+  Pair(Namespaces.mathml, "mtext")
 ];
 
-const spaceCharacters = ' \n\r\t\u000C';
+const spaceCharacters = " \n\r\t\u000C";
 
 const int NEWLINE = 10;
 const int RETURN = 13;
@@ -421,11 +422,11 @@
 }
 
 const List<String> tableInsertModeElements = [
-  'table',
-  'tbody',
-  'tfoot',
-  'thead',
-  'tr'
+  "table",
+  "tbody",
+  "tfoot",
+  "thead",
+  "tr"
 ];
 
 // TODO(jmesserly): remove these in favor of the test functions
@@ -442,13 +443,13 @@
 // Note: this is intentially ASCII only
 bool isLetter(String char) {
   if (char == null) return false;
-  var cc = char.codeUnitAt(0);
+  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;
-  var cc = char.codeUnitAt(0);
+  int cc = char.codeUnitAt(0);
   return cc >= ZERO && cc < ZERO + 10;
 }
 
@@ -487,7 +488,7 @@
 String asciiUpper2Lower(String text) {
   if (text == null) return null;
   var result = List<int>(text.length);
-  for (var i = 0; i < text.length; i++) {
+  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;
@@ -498,7 +499,7 @@
 }
 
 // Heading elements need to be ordered
-const headingElements = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
+const headingElements = ["h1", "h2", "h3", "h4", "h5", "h6"];
 
 const cdataElements = ['title', 'textarea'];
 
@@ -512,6 +513,44 @@
   'noscript'
 ];
 
+const Map<String, List<String>> booleanAttributes = {
+  "": [
+    "irrelevant",
+  ],
+  "style": [
+    "scoped",
+  ],
+  "img": [
+    "ismap",
+  ],
+  "audio": ["autoplay", "controls"],
+  "video": ["autoplay", "controls"],
+  "script": ["defer", "async"],
+  "details": [
+    "open",
+  ],
+  "datagrid": ["multiple", "disabled"],
+  "command": ["hidden", "disabled", "checked", "default"],
+  "hr": ["noshade"],
+  "men": [
+    "autosubmit",
+  ],
+  "fieldset": ["disabled", "readonly"],
+  "option": ["disabled", "readonly", "selected"],
+  "optgroup": ["disabled", "readonly"],
+  "button": ["disabled", "autofocus"],
+  "input": [
+    "disabled",
+    "readonly",
+    "required",
+    "autofocus",
+    "checked",
+    "ismap"
+  ],
+  "select": ["disabled", "readonly", "autofocus", "multiple"],
+  "output": ["disabled", "readonly"],
+};
+
 // entitiesWindows1252 has to be _ordered_ and needs to have an index. It
 // therefore can't be a frozenset.
 const List<int> entitiesWindows1252 = [
@@ -552,2274 +591,2274 @@
 const xmlEntities = ['lt;', 'gt;', 'amp;', 'apos;', 'quot;'];
 
 const Map<String, String> entities = {
-  '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',
+  "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",
 };
 
 const Map<int, String> replacementCharacters = {
-  0x00: '\uFFFD',
-  0x0d: '\u000D',
-  0x80: '\u20AC',
-  0x81: '\u0081',
-  0x82: '\u201A',
-  0x83: '\u0192',
-  0x84: '\u201E',
-  0x85: '\u2026',
-  0x86: '\u2020',
-  0x87: '\u2021',
-  0x88: '\u02C6',
-  0x89: '\u2030',
-  0x8A: '\u0160',
-  0x8B: '\u2039',
-  0x8C: '\u0152',
-  0x8D: '\u008D',
-  0x8E: '\u017D',
-  0x8F: '\u008F',
-  0x90: '\u0090',
-  0x91: '\u2018',
-  0x92: '\u2019',
-  0x93: '\u201C',
-  0x94: '\u201D',
-  0x95: '\u2022',
-  0x96: '\u2013',
-  0x97: '\u2014',
-  0x98: '\u02DC',
-  0x99: '\u2122',
-  0x9A: '\u0161',
-  0x9B: '\u203A',
-  0x9C: '\u0153',
-  0x9D: '\u009D',
-  0x9E: '\u017E',
-  0x9F: '\u0178'
+  0x00: "\uFFFD",
+  0x0d: "\u000D",
+  0x80: "\u20AC",
+  0x81: "\u0081",
+  0x82: "\u201A",
+  0x83: "\u0192",
+  0x84: "\u201E",
+  0x85: "\u2026",
+  0x86: "\u2020",
+  0x87: "\u2021",
+  0x88: "\u02C6",
+  0x89: "\u2030",
+  0x8A: "\u0160",
+  0x8B: "\u2039",
+  0x8C: "\u0152",
+  0x8D: "\u008D",
+  0x8E: "\u017D",
+  0x8F: "\u008F",
+  0x90: "\u0090",
+  0x91: "\u2018",
+  0x92: "\u2019",
+  0x93: "\u201C",
+  0x94: "\u201D",
+  0x95: "\u2022",
+  0x96: "\u2013",
+  0x97: "\u2014",
+  0x98: "\u02DC",
+  0x99: "\u2122",
+  0x9A: "\u0161",
+  0x9B: "\u203A",
+  0x9C: "\u0153",
+  0x9D: "\u009D",
+  0x9E: "\u017E",
+  0x9F: "\u0178"
 };
 
 const Map<String, String> encodings = {
diff --git a/html/lib/src/css_class_set.dart b/html/lib/src/css_class_set.dart
index 3fa49e0..939bf41 100644
--- a/html/lib/src/css_class_set.dart
+++ b/html/lib/src/css_class_set.dart
@@ -14,13 +14,12 @@
 
   ElementCssClassSet(this._element);
 
-  @override
   Set<String> readClasses() {
     var s = LinkedHashSet<String>();
     var classname = _element.className;
 
-    for (var name in classname.split(' ')) {
-      var trimmed = name.trim();
+    for (String name in classname.split(' ')) {
+      String trimmed = name.trim();
       if (trimmed.isNotEmpty) {
         s.add(trimmed);
       }
@@ -28,7 +27,6 @@
     return s;
   }
 
-  @override
   void writeClasses(Set<String> s) {
     _element.className = s.join(' ');
   }
@@ -51,7 +49,6 @@
   ///
   /// This is the Dart equivalent of jQuery's
   /// [hasClass](http://api.jquery.com/hasClass/).
-  @override
   bool contains(Object value);
 
   /// Add the class [value] to element.
@@ -63,7 +60,6 @@
   /// the set, otherwise false.
   ///
   /// If this corresponds to many elements, null is always returned.
-  @override
   bool add(String value);
 
   /// Remove the class [value] from element, and return true on successful
@@ -71,21 +67,18 @@
   ///
   /// This is the Dart equivalent of jQuery's
   /// [removeClass](http://api.jquery.com/removeClass/).
-  @override
   bool remove(Object value);
 
   /// Add all classes specified in [iterable] to element.
   ///
   /// This is the Dart equivalent of jQuery's
   /// [addClass](http://api.jquery.com/addClass/).
-  @override
   void addAll(Iterable<String> iterable);
 
   /// Remove all classes specified in [iterable] from element.
   ///
   /// This is the Dart equivalent of jQuery's
   /// [removeClass](http://api.jquery.com/removeClass/).
-  @override
   void removeAll(Iterable<Object> iterable);
 
   /// Toggles all classes specified in [iterable] on element.
@@ -100,7 +93,6 @@
 }
 
 abstract class _CssClassSetImpl extends SetBase<String> implements CssClassSet {
-  @override
   String toString() {
     return readClasses().join(' ');
   }
@@ -110,11 +102,10 @@
   ///
   /// If [shouldAdd] is true, then we always add that [value] to the element. If
   /// [shouldAdd] is false then we always remove [value] from the element.
-  @override
   bool toggle(String value, [bool shouldAdd]) {
-    var s = readClasses();
-    var result = false;
-    shouldAdd ??= !s.contains(value);
+    Set<String> s = readClasses();
+    bool result = false;
+    if (shouldAdd == null) shouldAdd = !s.contains(value);
     if (shouldAdd) {
       s.add(value);
       result = true;
@@ -127,13 +118,10 @@
 
   /// Returns [:true:] if classes cannot be added or removed from this
   /// [:CssClassSet:].
-  @override
   bool get frozen => false;
 
-  @override
   Iterator<String> get iterator => readClasses().iterator;
 
-  @override
   int get length => readClasses().length;
 
   // interface Set - BEGIN
@@ -141,21 +129,17 @@
   ///
   /// This is the Dart equivalent of jQuery's
   /// [hasClass](http://api.jquery.com/hasClass/).
-  @override
   bool contains(Object value) => readClasses().contains(value);
 
   /// Lookup from the Set interface. Not interesting for a String set.
-  @override
   String lookup(Object value) => contains(value) ? value as String : null;
 
-  @override
   Set<String> toSet() => readClasses().toSet();
 
   /// Add the class [value] to element.
   ///
   /// This is the Dart equivalent of jQuery's
   /// [addClass](http://api.jquery.com/addClass/).
-  @override
   bool add(String value) {
     // TODO - figure out if we need to do any validation here
     // or if the browser natively does enough.
@@ -167,11 +151,10 @@
   ///
   /// This is the Dart equivalent of jQuery's
   /// [removeClass](http://api.jquery.com/removeClass/).
-  @override
   bool remove(Object value) {
     if (value is! String) return false;
-    var s = readClasses();
-    var result = s.remove(value);
+    Set<String> s = readClasses();
+    bool result = s.remove(value);
     writeClasses(s);
     return result;
   }
@@ -184,7 +167,6 @@
   /// If [shouldAdd] is true, then we always add all the classes in [iterable]
   /// element. If [shouldAdd] is false then we always remove all the classes in
   /// [iterable] from the element.
-  @override
   void toggleAll(Iterable<String> iterable, [bool shouldAdd]) {
     iterable.forEach((e) => toggle(e, shouldAdd));
   }
@@ -196,8 +178,8 @@
   ///
   ///   After f returns, the modified set is written to the
   ///       className property of this element.
-  bool _modify(bool Function(Set<String>) f) {
-    var s = readClasses();
+  bool _modify(bool f(Set<String> s)) {
+    Set<String> s = readClasses();
     var ret = f(s);
     writeClasses(s);
     return ret;
diff --git a/html/lib/src/encoding_parser.dart b/html/lib/src/encoding_parser.dart
index 51766a9..d0f40d6 100644
--- a/html/lib/src/encoding_parser.dart
+++ b/html/lib/src/encoding_parser.dart
@@ -17,7 +17,7 @@
   String _next() {
     var p = __position = __position + 1;
     if (p >= _length) {
-      throw StateError('No more elements');
+      throw StateError("No more elements");
     } else if (p < 0) {
       throw RangeError(p);
     }
@@ -27,7 +27,7 @@
   String _previous() {
     var p = __position;
     if (p >= _length) {
-      throw StateError('No more elements');
+      throw StateError("No more elements");
     } else if (p < 0) {
       throw RangeError(p);
     }
@@ -37,14 +37,14 @@
 
   set _position(int value) {
     if (__position >= _length) {
-      throw StateError('No more elements');
+      throw StateError("No more elements");
     }
     __position = value;
   }
 
   int get _position {
     if (__position >= _length) {
-      throw StateError('No more elements');
+      throw StateError("No more elements");
     }
     if (__position >= 0) {
       return __position;
@@ -57,7 +57,7 @@
 
   /// Skip past a list of characters. Defaults to skipping [isWhitespace].
   String _skipChars([_CharPredicate skipChars]) {
-    skipChars ??= isWhitespace;
+    if (skipChars == null) skipChars = isWhitespace;
     var p = _position; // use property for the error-checking
     while (p < _length) {
       var c = _bytes[p];
@@ -108,12 +108,12 @@
       __position = newPosition + bytes.length - 1;
       return true;
     } else {
-      throw StateError('No more elements');
+      throw StateError("No more elements");
     }
   }
 
   String _slice(int start, [int end]) {
-    end ??= _length;
+    if (end == null) end = _length;
     if (end < 0) end += _length;
     return _bytes.substring(start, end);
   }
@@ -140,12 +140,12 @@
 
   String getEncoding() {
     final methodDispatch = [
-      _DispatchEntry('<!--', _handleComment),
-      _DispatchEntry('<meta', _handleMeta),
-      _DispatchEntry('</', _handlePossibleEndTag),
-      _DispatchEntry('<!', _handleOther),
-      _DispatchEntry('<?', _handleOther),
-      _DispatchEntry('<', _handlePossibleStartTag),
+      _DispatchEntry("<!--", _handleComment),
+      _DispatchEntry("<meta", _handleMeta),
+      _DispatchEntry("</", _handlePossibleEndTag),
+      _DispatchEntry("<!", _handleOther),
+      _DispatchEntry("<?", _handleOther),
+      _DispatchEntry("<", _handlePossibleStartTag),
     ];
 
     try {
@@ -169,7 +169,7 @@
   }
 
   /// Skip over comments.
-  bool _handleComment() => _data._jumpTo('-->');
+  bool _handleComment() => _data._jumpTo("-->");
 
   bool _handleMeta() {
     if (!isWhitespace(_data._currentByte)) {
@@ -182,14 +182,14 @@
       var attr = _getAttribute();
       if (attr == null) return true;
 
-      if (attr[0] == 'charset') {
+      if (attr[0] == "charset") {
         var tentativeEncoding = attr[1];
         var codec = codecName(tentativeEncoding);
         if (codec != null) {
           _encoding = codec;
           return false;
         }
-      } else if (attr[0] == 'content') {
+      } else if (attr[0] == "content") {
         var contentParser = ContentAttrParser(EncodingBytes(attr[1]));
         var tentativeEncoding = contentParser.parse();
         var codec = codecName(tentativeEncoding);
@@ -221,7 +221,7 @@
     }
 
     var c = _data._skipUntil(_isSpaceOrAngleBracket);
-    if (c == '<') {
+    if (c == "<") {
       // return to the first step in the overall "two step" algorithm
       // reprocessing the < byte
       _data._previous();
@@ -235,15 +235,15 @@
     return true;
   }
 
-  bool _handleOther() => _data._jumpTo('>');
+  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));
+    var c = _data._skipChars((x) => x == "/" || isWhitespace(x));
     // Step 2
-    if (c == '>' || c == null) {
+    if (c == ">" || c == null) {
       return null;
     }
     // Step 3
@@ -253,15 +253,15 @@
     while (true) {
       if (c == null) {
         return null;
-      } else if (c == '=' && attrName.isNotEmpty) {
+      } else if (c == "=" && attrName.isNotEmpty) {
         break;
       } else if (isWhitespace(c)) {
         // Step 6!
         c = _data._skipChars();
         c = _data._next();
         break;
-      } else if (c == '/' || c == '>') {
-        return [attrName.join(), ''];
+      } else if (c == "/" || c == ">") {
+        return [attrName.join(), ""];
       } else if (isLetter(c)) {
         attrName.add(c.toLowerCase());
       } else {
@@ -271,9 +271,9 @@
       c = _data._next();
     }
     // Step 7
-    if (c != '=') {
+    if (c != "=") {
       _data._previous();
-      return [attrName.join(), ''];
+      return [attrName.join(), ""];
     }
     // Step 8
     _data._next();
@@ -298,8 +298,8 @@
           attrValue.add(c);
         }
       }
-    } else if (c == '>') {
-      return [attrName.join(), ''];
+    } else if (c == ">") {
+      return [attrName.join(), ""];
     } else if (c == null) {
       return null;
     } else if (isLetter(c)) {
@@ -332,10 +332,10 @@
     try {
       // Check if the attr name is charset
       // otherwise return
-      data._jumpTo('charset');
+      data._jumpTo("charset");
       data._position += 1;
       data._skipChars();
-      if (data._currentByte != '=') {
+      if (data._currentByte != "=") {
         // If there is no = sign keep looking for attrs
         return null;
       }
@@ -369,7 +369,7 @@
 }
 
 bool _isSpaceOrAngleBracket(String char) {
-  return char == '>' || char == '<' || isWhitespace(char);
+  return char == ">" || char == "<" || isWhitespace(char);
 }
 
 typedef _CharPredicate = bool Function(String char);
diff --git a/html/lib/src/html_input_stream.dart b/html/lib/src/html_input_stream.dart
index 0b72da7..4590c5d 100644
--- a/html/lib/src/html_input_stream.dart
+++ b/html/lib/src/html_input_stream.dart
@@ -91,12 +91,14 @@
     _lineStarts = <int>[0];
     _chars = <int>[];
 
-    _rawChars ??= _decodeBytes(charEncodingName, _rawBytes);
+    if (_rawChars == null) {
+      _rawChars = _decodeBytes(charEncodingName, _rawBytes);
+    }
 
-    var skipNewline = false;
-    var wasSurrogatePair = false;
-    for (var i = 0; i < _rawChars.length; i++) {
-      var c = _rawChars[i];
+    bool skipNewline = false;
+    bool wasSurrogatePair = false;
+    for (int i = 0; i < _rawChars.length; i++) {
+      int c = _rawChars[i];
       if (skipNewline) {
         skipNewline = false;
         if (c == NEWLINE) continue;
@@ -239,7 +241,7 @@
   /// 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]) {
-    var start = _offset;
+    int start = _offset;
     String c;
     while ((c = peekChar()) != null && characters.contains(c) == opposite) {
       _offset += c.codeUnits.length;
@@ -311,7 +313,7 @@
 /// string doesn't correspond to a valid encoding.
 String codecName(String encoding) {
   final asciiPunctuation = RegExp(
-      '[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]');
+      "[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]");
 
   if (encoding == null) return null;
   var canonicalName = encoding.replaceAll(asciiPunctuation, '').toLowerCase();
@@ -322,7 +324,7 @@
 /// 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]) {
-  var end = length != null ? offset + length : bytes.length;
+  int end = length != null ? offset + length : bytes.length;
   return (offset + 3) <= end &&
       bytes[offset] == 0xEF &&
       bytes[offset + 1] == 0xBB &&
diff --git a/html/lib/src/list_proxy.dart b/html/lib/src/list_proxy.dart
index ef271ab..63aeea6 100644
--- a/html/lib/src/list_proxy.dart
+++ b/html/lib/src/list_proxy.dart
@@ -7,52 +7,40 @@
   /// The inner [List<T>] with the actual storage.
   final List<E> _list = <E>[];
 
-  @override
   bool remove(Object item) => _list.remove(item);
 
-  @override
   int get length => _list.length;
 
   // From Iterable
-  @override
   Iterator<E> get iterator => _list.iterator;
 
   // From List
-  @override
   E operator [](int index) => _list[index];
 
-  @override
   operator []=(int index, E value) {
     _list[index] = value;
   }
 
-  @override
   set length(int value) {
     _list.length = value;
   }
 
-  @override
   void add(E value) {
     _list.add(value);
   }
 
-  @override
   void insert(int index, E item) => _list.insert(index, item);
 
-  @override
   void addAll(Iterable<E> collection) {
     _list.addAll(collection);
   }
 
-  @override
   void insertAll(int index, Iterable<E> iterable) {
     _list.insertAll(index, iterable);
   }
 
-  @override
   E removeAt(int index) => _list.removeAt(index);
 
-  @override
   void removeRange(int start, int length) {
     _list.removeRange(start, length);
   }
diff --git a/html/lib/src/query_selector.dart b/html/lib/src/query_selector.dart
index 0c660b7..0503707 100644
--- a/html/lib/src/query_selector.dart
+++ b/html/lib/src/query_selector.dart
@@ -58,11 +58,9 @@
     }
   }
 
-  @override
   bool visitSelectorGroup(SelectorGroup group) =>
       group.selectors.any(visitSelector);
 
-  @override
   bool visitSelector(Selector selector) {
     var old = _element;
     var result = true;
@@ -125,14 +123,13 @@
     return result;
   }
 
-  UnimplementedError _unimplemented(SimpleSelector selector) =>
+  _unimplemented(SimpleSelector selector) =>
       UnimplementedError("'$selector' selector of type "
-          '${selector.runtimeType} is not implemented');
+          "${selector.runtimeType} is not implemented");
 
-  FormatException _unsupported(selector) =>
+  _unsupported(selector) =>
       FormatException("'$selector' is not a valid selector");
 
-  @override
   bool visitPseudoClassSelector(PseudoClassSelector selector) {
     switch (selector.name) {
       // http://dev.w3.org/csswg/selectors-4/#structural-pseudos
@@ -182,7 +179,6 @@
     throw _unimplemented(selector);
   }
 
-  @override
   bool visitPseudoElementSelector(PseudoElementSelector selector) {
     // :before, :after, :first-letter/line can't match DOM elements.
     if (_isLegacyPsuedoClass(selector.name)) return false;
@@ -202,11 +198,9 @@
     }
   }
 
-  @override
   bool visitPseudoElementFunctionSelector(PseudoElementFunctionSelector s) =>
       throw _unimplemented(s);
 
-  @override
   bool visitPseudoClassFunctionSelector(PseudoClassFunctionSelector selector) {
     switch (selector.name) {
       // http://dev.w3.org/csswg/selectors-4/#child-index
@@ -245,7 +239,6 @@
     return null;
   }
 
-  @override
   bool visitNamespaceSelector(NamespaceSelector selector) {
     // Match element tag name
     if (!selector.nameAsSimpleSelector.visit(this)) return false;
@@ -257,25 +250,20 @@
     throw _unimplemented(selector);
   }
 
-  @override
   bool visitElementSelector(ElementSelector selector) =>
       selector.isWildcard || _element.localName == selector.name.toLowerCase();
 
-  @override
   bool visitIdSelector(IdSelector selector) => _element.id == selector.name;
 
-  @override
   bool visitClassSelector(ClassSelector selector) =>
       _element.classes.contains(selector.name);
 
   // TODO(jmesserly): negation should support any selectors in level 4,
   // not just simple selectors.
   // http://dev.w3.org/csswg/selectors-4/#negation
-  @override
   bool visitNegationSelector(NegationSelector selector) =>
       !selector.negationArg.visit(this);
 
-  @override
   bool visitAttributeSelector(AttributeSelector selector) {
     // Match name first
     var value = _element.attributes[selector.name.toLowerCase()];
diff --git a/html/lib/src/token.dart b/html/lib/src/token.dart
index e92ec8e..ea0a855 100644
--- a/html/lib/src/token.dart
+++ b/html/lib/src/token.dart
@@ -39,7 +39,6 @@
       this.namespace})
       : super(name, selfClosing);
 
-  @override
   int get kind => TokenKind.startTag;
 }
 
@@ -47,7 +46,6 @@
   EndTagToken(String name, {bool selfClosing = false})
       : super(name, selfClosing);
 
-  @override
   int get kind => TokenKind.endTag;
 }
 
@@ -79,14 +77,12 @@
 
   ParseErrorToken(String data, {this.messageParams}) : super(data);
 
-  @override
   int get kind => TokenKind.parseError;
 }
 
 class CharactersToken extends StringToken {
   CharactersToken([String data]) : super(data);
 
-  @override
   int get kind => TokenKind.characters;
 
   /// Replaces the token's [data]. This should only be used to wholly replace
@@ -100,26 +96,23 @@
 class SpaceCharactersToken extends StringToken {
   SpaceCharactersToken([String data]) : super(data);
 
-  @override
   int get kind => TokenKind.spaceCharacters;
 }
 
 class CommentToken extends StringToken {
   CommentToken([String data]) : super(data);
 
-  @override
   int get kind => TokenKind.comment;
 }
 
 class DoctypeToken extends Token {
   String publicId;
   String systemId;
-  String name = '';
+  String name = "";
   bool correct;
 
   DoctypeToken({this.publicId, this.systemId, this.correct = false});
 
-  @override
   int get kind => TokenKind.doctype;
 }
 
diff --git a/html/lib/src/tokenizer.dart b/html/lib/src/tokenizer.dart
index b26e8d9..638663e 100644
--- a/html/lib/src/tokenizer.dart
+++ b/html/lib/src/tokenizer.dart
@@ -84,7 +84,6 @@
   StringToken get currentStringToken => currentToken;
 
   Token _current;
-  @override
   Token get current => _current;
 
   final StringBuffer _attributeName = StringBuffer();
@@ -108,7 +107,7 @@
   void _markAttributeNameEnd(int offset) => _markAttributeEnd(offset);
 
   void _addAttribute(String name) {
-    _attributes ??= [];
+    if (_attributes == null) _attributes = [];
     _attributeName.clear();
     _attributeName.write(name);
     _attributeValue.clear();
@@ -122,7 +121,6 @@
   /// 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.
-  @override
   bool moveNext() {
     // Start processing. When EOF is reached state will return false;
     // instead of true and the loop will terminate.
@@ -156,7 +154,7 @@
   /// Adds a token to the queue. Sets the span if needed.
   void _addToken(Token token) {
     if (generateSpans && token.span == null) {
-      var offset = stream.position;
+      int offset = stream.position;
       token.span = stream.fileInfo.span(_lastOffset, offset);
       if (token is! ParseErrorToken) {
         _lastOffset = offset;
@@ -187,18 +185,18 @@
     }
 
     // Convert the set of characters consumed to an int.
-    var charAsInt = int.parse(charStack.join(), radix: radix);
+    var charAsInt = parseIntRadix(charStack.join(), radix);
 
     // Certain characters get replaced with others
     var char = replacementCharacters[charAsInt];
     if (char != null) {
-      _addToken(ParseErrorToken('illegal-codepoint-for-numeric-entity',
-          messageParams: {'charAsInt': charAsInt}));
+      _addToken(ParseErrorToken("illegal-codepoint-for-numeric-entity",
+          messageParams: {"charAsInt": charAsInt}));
     } else if ((0xD800 <= charAsInt && charAsInt <= 0xDFFF) ||
         (charAsInt > 0x10FFFF)) {
-      char = '\uFFFD';
-      _addToken(ParseErrorToken('illegal-codepoint-for-numeric-entity',
-          messageParams: {'charAsInt': charAsInt}));
+      char = "\uFFFD";
+      _addToken(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) ||
@@ -242,16 +240,16 @@
             0x10FFFE,
             0x10FFFF
           ].contains(charAsInt)) {
-        _addToken(ParseErrorToken('illegal-codepoint-for-numeric-entity',
-            messageParams: {'charAsInt': charAsInt}));
+        _addToken(ParseErrorToken("illegal-codepoint-for-numeric-entity",
+            messageParams: {"charAsInt": charAsInt}));
       }
       char = String.fromCharCodes([charAsInt]);
     }
 
     // Discard the ; if present. Otherwise, put it back on the queue and
     // invoke parseError on parser.
-    if (c != ';') {
-      _addToken(ParseErrorToken('numeric-entity-without-semicolon'));
+    if (c != ";") {
+      _addToken(ParseErrorToken("numeric-entity-without-semicolon"));
       stream.unget(c);
     }
     return char;
@@ -259,7 +257,7 @@
 
   void consumeEntity({String allowedChar, bool fromAttribute = false}) {
     // Initialise to the default output for when no entity is matched
-    var output = '&';
+    var output = "&";
 
     var charStack = [stream.char()];
     if (isWhitespace(charStack[0]) ||
@@ -268,9 +266,9 @@
         charStack[0] == eof ||
         allowedChar == charStack[0]) {
       stream.unget(charStack[0]);
-    } else if (charStack[0] == '#') {
+    } else if (charStack[0] == "#") {
       // Read the next character to see if it's hex or decimal
-      var hex = false;
+      bool hex = false;
       charStack.add(stream.char());
       if (charStack.last == 'x' || charStack.last == 'X') {
         hex = true;
@@ -285,9 +283,9 @@
         output = consumeNumberEntity(hex);
       } else {
         // No digits found
-        _addToken(ParseErrorToken('expected-numeric-entity'));
+        _addToken(ParseErrorToken("expected-numeric-entity"));
         stream.unget(charStack.removeLast());
-        output = '&${charStack.join()}';
+        output = "&${charStack.join()}";
       }
     } else {
       // At this point in the process might have named entity. Entities
@@ -295,7 +293,8 @@
       //
       // Consume characters and compare to these to a substring of the
       // entity names in the list until the substring no longer matches.
-      var filteredEntityList = entitiesByFirstChar[charStack[0]] ?? const [];
+      var filteredEntityList = entitiesByFirstChar[charStack[0]];
+      if (filteredEntityList == null) filteredEntityList = const [];
 
       while (charStack.last != eof) {
         var name = charStack.join();
@@ -326,24 +325,24 @@
 
       if (entityName != null) {
         var lastChar = entityName[entityName.length - 1];
-        if (lastChar != ';') {
-          _addToken(ParseErrorToken('named-entity-without-semicolon'));
+        if (lastChar != ";") {
+          _addToken(ParseErrorToken("named-entity-without-semicolon"));
         }
-        if (lastChar != ';' &&
+        if (lastChar != ";" &&
             fromAttribute &&
             (isLetterOrDigit(charStack[entityLen]) ||
                 charStack[entityLen] == '=')) {
           stream.unget(charStack.removeLast());
-          output = '&${charStack.join()}';
+          output = "&${charStack.join()}";
         } else {
           output = entities[entityName];
           stream.unget(charStack.removeLast());
           output = '$output${slice(charStack, entityLen).join()}';
         }
       } else {
-        _addToken(ParseErrorToken('expected-named-entity'));
+        _addToken(ParseErrorToken("expected-named-entity"));
         stream.unget(charStack.removeLast());
-        output = '&${charStack.join()}';
+        output = "&${charStack.join()}";
       }
     }
     if (fromAttribute) {
@@ -376,10 +375,10 @@
       }
       if (token is EndTagToken) {
         if (_attributes != null) {
-          _addToken(ParseErrorToken('attributes-in-end-tag'));
+          _addToken(ParseErrorToken("attributes-in-end-tag"));
         }
         if (token.selfClosing) {
-          _addToken(ParseErrorToken('this-closing-flag-on-end-tag'));
+          _addToken(ParseErrorToken("this-closing-flag-on-end-tag"));
         }
       } else if (token is StartTagToken) {
         // HTML5 specific normalizations to the token stream.
@@ -403,13 +402,13 @@
 
   bool dataState() {
     var data = stream.char();
-    if (data == '&') {
+    if (data == "&") {
       state = entityDataState;
-    } else if (data == '<') {
+    } else if (data == "<") {
       state = tagOpenState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\u0000'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\u0000"));
     } else if (data == eof) {
       // Tokenization ends.
       return false;
@@ -423,7 +422,7 @@
       // have already been appended to lastFourChars and will have broken
       // any <!-- or --> sequences
     } else {
-      var chars = stream.charsUntil('&<\u0000');
+      var chars = stream.charsUntil("&<\u0000");
       _addToken(CharactersToken('$data$chars'));
     }
     return true;
@@ -437,16 +436,16 @@
 
   bool rcdataState() {
     var data = stream.char();
-    if (data == '&') {
+    if (data == "&") {
       state = characterReferenceInRcdata;
-    } else if (data == '<') {
+    } else if (data == "<") {
       state = rcdataLessThanSignState;
     } else if (data == eof) {
       // Tokenization ends.
       return false;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(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
@@ -454,7 +453,7 @@
       _addToken(SpaceCharactersToken(
           '$data${stream.charsUntil(spaceCharacters, true)}'));
     } else {
-      var chars = stream.charsUntil('&<');
+      var chars = stream.charsUntil("&<");
       _addToken(CharactersToken('$data$chars'));
     }
     return true;
@@ -468,34 +467,34 @@
 
   bool rawtextState() {
     var data = stream.char();
-    if (data == '<') {
+    if (data == "<") {
       state = rawtextLessThanSignState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
     } else if (data == eof) {
       // Tokenization ends.
       return false;
     } else {
-      var chars = stream.charsUntil('<\u0000');
-      _addToken(CharactersToken('$data$chars'));
+      var chars = stream.charsUntil("<\u0000");
+      _addToken(CharactersToken("$data$chars"));
     }
     return true;
   }
 
   bool scriptDataState() {
     var data = stream.char();
-    if (data == '<') {
+    if (data == "<") {
       state = scriptDataLessThanSignState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
     } else if (data == eof) {
       // Tokenization ends.
       return false;
     } else {
-      var chars = stream.charsUntil('<\u0000');
-      _addToken(CharactersToken('$data$chars'));
+      var chars = stream.charsUntil("<\u0000");
+      _addToken(CharactersToken("$data$chars"));
     }
     return true;
   }
@@ -505,9 +504,9 @@
     if (data == eof) {
       // Tokenization ends.
       return false;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
     } else {
       _addToken(CharactersToken('$data${stream.charsUntil("\u0000")}'));
     }
@@ -516,29 +515,29 @@
 
   bool tagOpenState() {
     var data = stream.char();
-    if (data == '!') {
+    if (data == "!") {
       state = markupDeclarationOpenState;
-    } else if (data == '/') {
+    } else if (data == "/") {
       state = closeTagOpenState;
     } else if (isLetter(data)) {
       currentToken = StartTagToken(data);
       state = tagNameState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       // XXX In theory it could be something besides a tag name. But
       // do we really care?
-      _addToken(ParseErrorToken('expected-tag-name-but-got-right-bracket'));
-      _addToken(CharactersToken('<>'));
+      _addToken(ParseErrorToken("expected-tag-name-but-got-right-bracket"));
+      _addToken(CharactersToken("<>"));
       state = dataState;
-    } else if (data == '?') {
+    } else if (data == "?") {
       // XXX In theory it could be something besides a tag name. But
       // do we really care?
-      _addToken(ParseErrorToken('expected-tag-name-but-got-question-mark'));
+      _addToken(ParseErrorToken("expected-tag-name-but-got-question-mark"));
       stream.unget(data);
       state = bogusCommentState;
     } else {
       // XXX
-      _addToken(ParseErrorToken('expected-tag-name'));
-      _addToken(CharactersToken('<'));
+      _addToken(ParseErrorToken("expected-tag-name"));
+      _addToken(CharactersToken("<"));
       stream.unget(data);
       state = dataState;
     }
@@ -550,17 +549,17 @@
     if (isLetter(data)) {
       currentToken = EndTagToken(data);
       state = tagNameState;
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('expected-closing-tag-but-got-right-bracket'));
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("expected-closing-tag-but-got-right-bracket"));
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('expected-closing-tag-but-got-eof'));
-      _addToken(CharactersToken('</'));
+      _addToken(ParseErrorToken("expected-closing-tag-but-got-eof"));
+      _addToken(CharactersToken("</"));
       state = dataState;
     } else {
       // XXX data can be _'_...
-      _addToken(ParseErrorToken('expected-closing-tag-but-got-char',
-          messageParams: {'data': data}));
+      _addToken(ParseErrorToken("expected-closing-tag-but-got-char",
+          messageParams: {"data": data}));
       stream.unget(data);
       state = bogusCommentState;
     }
@@ -571,15 +570,15 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       state = beforeAttributeNameState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       emitCurrentToken();
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-tag-name'));
+      _addToken(ParseErrorToken("eof-in-tag-name"));
       state = dataState;
-    } else if (data == '/') {
+    } else if (data == "/") {
       state = selfClosingStartTagState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       currentTagToken.name = '${currentTagToken.name}\uFFFD';
     } else {
       currentTagToken.name = '${currentTagToken.name}$data';
@@ -591,11 +590,11 @@
 
   bool rcdataLessThanSignState() {
     var data = stream.char();
-    if (data == '/') {
+    if (data == "/") {
       _buffer.clear();
       state = rcdataEndTagOpenState;
     } else {
-      _addToken(CharactersToken('<'));
+      _addToken(CharactersToken("<"));
       stream.unget(data);
       state = rcdataState;
     }
@@ -608,7 +607,7 @@
       _buffer.write(data);
       state = rcdataEndTagNameState;
     } else {
-      _addToken(CharactersToken('</'));
+      _addToken(CharactersToken("</"));
       stream.unget(data);
       state = rcdataState;
     }
@@ -627,17 +626,17 @@
     if (isWhitespace(data) && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = beforeAttributeNameState;
-    } else if (data == '/' && appropriate) {
+    } else if (data == "/" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = selfClosingStartTagState;
-    } else if (data == '>' && appropriate) {
+    } else if (data == ">" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       emitCurrentToken();
       state = dataState;
     } else if (isLetter(data)) {
       _buffer.write(data);
     } else {
-      _addToken(CharactersToken('</$_buffer'));
+      _addToken(CharactersToken("</$_buffer"));
       stream.unget(data);
       state = rcdataState;
     }
@@ -646,11 +645,11 @@
 
   bool rawtextLessThanSignState() {
     var data = stream.char();
-    if (data == '/') {
+    if (data == "/") {
       _buffer.clear();
       state = rawtextEndTagOpenState;
     } else {
-      _addToken(CharactersToken('<'));
+      _addToken(CharactersToken("<"));
       stream.unget(data);
       state = rawtextState;
     }
@@ -663,7 +662,7 @@
       _buffer.write(data);
       state = rawtextEndTagNameState;
     } else {
-      _addToken(CharactersToken('</'));
+      _addToken(CharactersToken("</"));
       stream.unget(data);
       state = rawtextState;
     }
@@ -676,17 +675,17 @@
     if (isWhitespace(data) && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = beforeAttributeNameState;
-    } else if (data == '/' && appropriate) {
+    } else if (data == "/" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = selfClosingStartTagState;
-    } else if (data == '>' && appropriate) {
+    } else if (data == ">" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       emitCurrentToken();
       state = dataState;
     } else if (isLetter(data)) {
       _buffer.write(data);
     } else {
-      _addToken(CharactersToken('</$_buffer'));
+      _addToken(CharactersToken("</$_buffer"));
       stream.unget(data);
       state = rawtextState;
     }
@@ -695,14 +694,14 @@
 
   bool scriptDataLessThanSignState() {
     var data = stream.char();
-    if (data == '/') {
+    if (data == "/") {
       _buffer.clear();
       state = scriptDataEndTagOpenState;
-    } else if (data == '!') {
-      _addToken(CharactersToken('<!'));
+    } else if (data == "!") {
+      _addToken(CharactersToken("<!"));
       state = scriptDataEscapeStartState;
     } else {
-      _addToken(CharactersToken('<'));
+      _addToken(CharactersToken("<"));
       stream.unget(data);
       state = scriptDataState;
     }
@@ -715,7 +714,7 @@
       _buffer.write(data);
       state = scriptDataEndTagNameState;
     } else {
-      _addToken(CharactersToken('</'));
+      _addToken(CharactersToken("</"));
       stream.unget(data);
       state = scriptDataState;
     }
@@ -728,17 +727,17 @@
     if (isWhitespace(data) && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = beforeAttributeNameState;
-    } else if (data == '/' && appropriate) {
+    } else if (data == "/" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = selfClosingStartTagState;
-    } else if (data == '>' && appropriate) {
+    } else if (data == ">" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       emitCurrentToken();
       state = dataState;
     } else if (isLetter(data)) {
       _buffer.write(data);
     } else {
-      _addToken(CharactersToken('</$_buffer'));
+      _addToken(CharactersToken("</$_buffer"));
       stream.unget(data);
       state = scriptDataState;
     }
@@ -747,8 +746,8 @@
 
   bool scriptDataEscapeStartState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
       state = scriptDataEscapeStartDashState;
     } else {
       stream.unget(data);
@@ -759,8 +758,8 @@
 
   bool scriptDataEscapeStartDashState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
       state = scriptDataEscapedDashDashState;
     } else {
       stream.unget(data);
@@ -771,33 +770,33 @@
 
   bool scriptDataEscapedState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
       state = scriptDataEscapedDashState;
-    } else if (data == '<') {
+    } else if (data == "<") {
       state = scriptDataEscapedLessThanSignState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
     } else if (data == eof) {
       state = dataState;
     } else {
-      var chars = stream.charsUntil('<-\u0000');
-      _addToken(CharactersToken('$data$chars'));
+      var chars = stream.charsUntil("<-\u0000");
+      _addToken(CharactersToken("$data$chars"));
     }
     return true;
   }
 
   bool scriptDataEscapedDashState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
       state = scriptDataEscapedDashDashState;
-    } else if (data == '<') {
+    } else if (data == "<") {
       state = scriptDataEscapedLessThanSignState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
       state = scriptDataEscapedState;
     } else if (data == eof) {
       state = dataState;
@@ -810,16 +809,16 @@
 
   bool scriptDataEscapedDashDashState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
-    } else if (data == '<') {
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
+    } else if (data == "<") {
       state = scriptDataEscapedLessThanSignState;
-    } else if (data == '>') {
-      _addToken(CharactersToken('>'));
+    } else if (data == ">") {
+      _addToken(CharactersToken(">"));
       state = scriptDataState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
       state = scriptDataEscapedState;
     } else if (data == eof) {
       state = dataState;
@@ -832,16 +831,16 @@
 
   bool scriptDataEscapedLessThanSignState() {
     var data = stream.char();
-    if (data == '/') {
+    if (data == "/") {
       _buffer.clear();
       state = scriptDataEscapedEndTagOpenState;
     } else if (isLetter(data)) {
-      _addToken(CharactersToken('<$data'));
+      _addToken(CharactersToken("<$data"));
       _buffer.clear();
       _buffer.write(data);
       state = scriptDataDoubleEscapeStartState;
     } else {
-      _addToken(CharactersToken('<'));
+      _addToken(CharactersToken("<"));
       stream.unget(data);
       state = scriptDataEscapedState;
     }
@@ -855,7 +854,7 @@
       _buffer.write(data);
       state = scriptDataEscapedEndTagNameState;
     } else {
-      _addToken(CharactersToken('</'));
+      _addToken(CharactersToken("</"));
       stream.unget(data);
       state = scriptDataEscapedState;
     }
@@ -868,17 +867,17 @@
     if (isWhitespace(data) && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = beforeAttributeNameState;
-    } else if (data == '/' && appropriate) {
+    } else if (data == "/" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       state = selfClosingStartTagState;
-    } else if (data == '>' && appropriate) {
+    } else if (data == ">" && appropriate) {
       currentToken = EndTagToken('$_buffer');
       emitCurrentToken();
       state = dataState;
     } else if (isLetter(data)) {
       _buffer.write(data);
     } else {
-      _addToken(CharactersToken('</$_buffer'));
+      _addToken(CharactersToken("</$_buffer"));
       stream.unget(data);
       state = scriptDataEscapedState;
     }
@@ -887,9 +886,9 @@
 
   bool scriptDataDoubleEscapeStartState() {
     var data = stream.char();
-    if (isWhitespace(data) || data == '/' || data == '>') {
+    if (isWhitespace(data) || data == "/" || data == ">") {
       _addToken(CharactersToken(data));
-      if ('$_buffer'.toLowerCase() == 'script') {
+      if ('$_buffer'.toLowerCase() == "script") {
         state = scriptDataDoubleEscapedState;
       } else {
         state = scriptDataEscapedState;
@@ -906,17 +905,17 @@
 
   bool scriptDataDoubleEscapedState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
       state = scriptDataDoubleEscapedDashState;
-    } else if (data == '<') {
-      _addToken(CharactersToken('<'));
+    } else if (data == "<") {
+      _addToken(CharactersToken("<"));
       state = scriptDataDoubleEscapedLessThanSignState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-script-in-script'));
+      _addToken(ParseErrorToken("eof-in-script-in-script"));
       state = dataState;
     } else {
       _addToken(CharactersToken(data));
@@ -926,18 +925,18 @@
 
   bool scriptDataDoubleEscapedDashState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
       state = scriptDataDoubleEscapedDashDashState;
-    } else if (data == '<') {
-      _addToken(CharactersToken('<'));
+    } else if (data == "<") {
+      _addToken(CharactersToken("<"));
       state = scriptDataDoubleEscapedLessThanSignState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
       state = scriptDataDoubleEscapedState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-script-in-script'));
+      _addToken(ParseErrorToken("eof-in-script-in-script"));
       state = dataState;
     } else {
       _addToken(CharactersToken(data));
@@ -950,20 +949,20 @@
   // (was "Dash" instead of "DashDash")
   bool scriptDataDoubleEscapedDashDashState() {
     var data = stream.char();
-    if (data == '-') {
-      _addToken(CharactersToken('-'));
-    } else if (data == '<') {
-      _addToken(CharactersToken('<'));
+    if (data == "-") {
+      _addToken(CharactersToken("-"));
+    } else if (data == "<") {
+      _addToken(CharactersToken("<"));
       state = scriptDataDoubleEscapedLessThanSignState;
-    } else if (data == '>') {
-      _addToken(CharactersToken('>'));
+    } else if (data == ">") {
+      _addToken(CharactersToken(">"));
       state = scriptDataState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addToken(CharactersToken('\uFFFD'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addToken(CharactersToken("\uFFFD"));
       state = scriptDataDoubleEscapedState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-script-in-script'));
+      _addToken(ParseErrorToken("eof-in-script-in-script"));
       state = dataState;
     } else {
       _addToken(CharactersToken(data));
@@ -974,8 +973,8 @@
 
   bool scriptDataDoubleEscapedLessThanSignState() {
     var data = stream.char();
-    if (data == '/') {
-      _addToken(CharactersToken('/'));
+    if (data == "/") {
+      _addToken(CharactersToken("/"));
       _buffer.clear();
       state = scriptDataDoubleEscapeEndState;
     } else {
@@ -987,9 +986,9 @@
 
   bool scriptDataDoubleEscapeEndState() {
     var data = stream.char();
-    if (isWhitespace(data) || data == '/' || data == '>') {
+    if (isWhitespace(data) || data == "/" || data == ">") {
       _addToken(CharactersToken(data));
-      if ('$_buffer'.toLowerCase() == 'script') {
+      if ('$_buffer'.toLowerCase() == "script") {
         state = scriptDataEscapedState;
       } else {
         state = scriptDataDoubleEscapedState;
@@ -1011,20 +1010,20 @@
     } else if (isLetter(data)) {
       _addAttribute(data);
       state = attributeNameState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       emitCurrentToken();
-    } else if (data == '/') {
+    } else if (data == "/") {
       state = selfClosingStartTagState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('expected-attribute-name-but-got-eof'));
+      _addToken(ParseErrorToken("expected-attribute-name-but-got-eof"));
       state = dataState;
     } else if ("'\"=<".contains(data)) {
-      _addToken(ParseErrorToken('invalid-character-in-attribute-name'));
+      _addToken(ParseErrorToken("invalid-character-in-attribute-name"));
       _addAttribute(data);
       state = attributeNameState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addAttribute('\uFFFD');
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addAttribute("\uFFFD");
       state = attributeNameState;
     } else {
       _addAttribute(data);
@@ -1035,32 +1034,32 @@
 
   bool attributeNameState() {
     var data = stream.char();
-    var leavingThisState = true;
-    var emitToken = false;
-    if (data == '=') {
+    bool leavingThisState = true;
+    bool emitToken = false;
+    if (data == "=") {
       state = beforeAttributeValueState;
     } else if (isLetter(data)) {
       _attributeName.write(data);
       _attributeName.write(stream.charsUntil(asciiLetters, true));
       leavingThisState = false;
-    } else if (data == '>') {
+    } 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 == '/') {
+    } else if (data == "/") {
       state = selfClosingStartTagState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       _attributeName.write('\uFFFD');
       leavingThisState = false;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-attribute-name'));
+      _addToken(ParseErrorToken("eof-in-attribute-name"));
       state = dataState;
     } else if ("'\"<".contains(data)) {
-      _addToken(ParseErrorToken('invalid-character-in-attribute-name'));
+      _addToken(ParseErrorToken("invalid-character-in-attribute-name"));
       _attributeName.write(data);
       leavingThisState = false;
     } else {
@@ -1079,9 +1078,9 @@
         attrName = asciiUpper2Lower(attrName);
       }
       _attributes.last.name = attrName;
-      _attributeNames ??= {};
+      if (_attributeNames == null) _attributeNames = Set();
       if (_attributeNames.contains(attrName)) {
-        _addToken(ParseErrorToken('duplicate-attribute'));
+        _addToken(ParseErrorToken("duplicate-attribute"));
       }
       _attributeNames.add(attrName);
 
@@ -1097,24 +1096,24 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       stream.charsUntil(spaceCharacters, true);
-    } else if (data == '=') {
+    } else if (data == "=") {
       state = beforeAttributeValueState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       emitCurrentToken();
     } else if (isLetter(data)) {
       _addAttribute(data);
       state = attributeNameState;
-    } else if (data == '/') {
+    } else if (data == "/") {
       state = selfClosingStartTagState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      _addAttribute('\uFFFD');
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      _addAttribute("\uFFFD");
       state = attributeNameState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('expected-end-of-tag-but-got-eof'));
+      _addToken(ParseErrorToken("expected-end-of-tag-but-got-eof"));
       state = dataState;
     } else if ("'\"<".contains(data)) {
-      _addToken(ParseErrorToken('invalid-character-after-attribute-name'));
+      _addToken(ParseErrorToken("invalid-character-after-attribute-name"));
       _addAttribute(data);
       state = attributeNameState;
     } else {
@@ -1128,30 +1127,30 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       stream.charsUntil(spaceCharacters, true);
-    } else if (data == '"') {
+    } else if (data == "\"") {
       _markAttributeValueStart(0);
       state = attributeValueDoubleQuotedState;
-    } else if (data == '&') {
+    } else if (data == "&") {
       state = attributeValueUnQuotedState;
       stream.unget(data);
       _markAttributeValueStart(0);
     } else if (data == "'") {
       _markAttributeValueStart(0);
       state = attributeValueSingleQuotedState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       _addToken(
-          ParseErrorToken('expected-attribute-value-but-got-right-bracket'));
+          ParseErrorToken("expected-attribute-value-but-got-right-bracket"));
       emitCurrentToken();
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       _markAttributeValueStart(-1);
       _attributeValue.write('\uFFFD');
       state = attributeValueUnQuotedState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('expected-attribute-value-but-got-eof'));
+      _addToken(ParseErrorToken("expected-attribute-value-but-got-eof"));
       state = dataState;
-    } else if ('=<`'.contains(data)) {
-      _addToken(ParseErrorToken('equals-in-unquoted-attribute-value'));
+    } else if ("=<`".contains(data)) {
+      _addToken(ParseErrorToken("equals-in-unquoted-attribute-value"));
       _markAttributeValueStart(-1);
       _attributeValue.write(data);
       state = attributeValueUnQuotedState;
@@ -1165,22 +1164,22 @@
 
   bool attributeValueDoubleQuotedState() {
     var data = stream.char();
-    if (data == '"') {
+    if (data == "\"") {
       _markAttributeValueEnd(-1);
       _markAttributeEnd(0);
       state = afterAttributeValueState;
-    } else if (data == '&') {
+    } else if (data == "&") {
       processEntityInAttribute('"');
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       _attributeValue.write('\uFFFD');
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-attribute-value-double-quote'));
+      _addToken(ParseErrorToken("eof-in-attribute-value-double-quote"));
       _markAttributeValueEnd(-1);
       state = dataState;
     } else {
       _attributeValue.write(data);
-      _attributeValue.write(stream.charsUntil('"&'));
+      _attributeValue.write(stream.charsUntil("\"&"));
     }
     return true;
   }
@@ -1191,13 +1190,13 @@
       _markAttributeValueEnd(-1);
       _markAttributeEnd(0);
       state = afterAttributeValueState;
-    } else if (data == '&') {
+    } else if (data == "&") {
       processEntityInAttribute("'");
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       _attributeValue.write('\uFFFD');
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-attribute-value-single-quote'));
+      _addToken(ParseErrorToken("eof-in-attribute-value-single-quote"));
       _markAttributeValueEnd(-1);
       state = dataState;
     } else {
@@ -1212,21 +1211,21 @@
     if (isWhitespace(data)) {
       _markAttributeValueEnd(-1);
       state = beforeAttributeNameState;
-    } else if (data == '&') {
-      processEntityInAttribute('>');
-    } else if (data == '>') {
+    } else if (data == "&") {
+      processEntityInAttribute(">");
+    } else if (data == ">") {
       _markAttributeValueEnd(-1);
       emitCurrentToken();
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-attribute-value-no-quotes'));
+      _addToken(ParseErrorToken("eof-in-attribute-value-no-quotes"));
       _markAttributeValueEnd(-1);
       state = dataState;
     } else if ('"\'=<`'.contains(data)) {
       _addToken(
-          ParseErrorToken('unexpected-character-in-unquoted-attribute-value'));
+          ParseErrorToken("unexpected-character-in-unquoted-attribute-value"));
       _attributeValue.write(data);
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       _attributeValue.write('\uFFFD');
     } else {
       _attributeValue.write(data);
@@ -1239,16 +1238,16 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       state = beforeAttributeNameState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       emitCurrentToken();
-    } else if (data == '/') {
+    } else if (data == "/") {
       state = selfClosingStartTagState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('unexpected-EOF-after-attribute-value'));
+      _addToken(ParseErrorToken("unexpected-EOF-after-attribute-value"));
       stream.unget(data);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('unexpected-character-after-attribute-value'));
+      _addToken(ParseErrorToken("unexpected-character-after-attribute-value"));
       stream.unget(data);
       state = beforeAttributeNameState;
     }
@@ -1257,15 +1256,15 @@
 
   bool selfClosingStartTagState() {
     var data = stream.char();
-    if (data == '>') {
+    if (data == ">") {
       currentTagToken.selfClosing = true;
       emitCurrentToken();
     } else if (data == eof) {
-      _addToken(ParseErrorToken('unexpected-EOF-after-solidus-in-tag'));
+      _addToken(ParseErrorToken("unexpected-EOF-after-solidus-in-tag"));
       stream.unget(data);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('unexpected-character-after-soldius-in-tag'));
+      _addToken(ParseErrorToken("unexpected-character-after-soldius-in-tag"));
       stream.unget(data);
       state = beforeAttributeNameState;
     }
@@ -1276,8 +1275,8 @@
     // 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');
+    var data = stream.charsUntil(">");
+    data = data.replaceAll("\u0000", "\uFFFD");
     _addToken(CommentToken(data));
 
     // Eat the character directly after the bogus comment which is either a
@@ -1289,9 +1288,9 @@
 
   bool markupDeclarationOpenState() {
     var charStack = [stream.char()];
-    if (charStack.last == '-') {
+    if (charStack.last == "-") {
       charStack.add(stream.char());
-      if (charStack.last == '-') {
+      if (charStack.last == "-") {
         currentToken = CommentToken();
         state = commentStartState;
         return true;
@@ -1311,13 +1310,13 @@
         state = doctypeState;
         return true;
       }
-    } else if (charStack.last == '[' &&
+    } else if (charStack.last == "[" &&
         parser != null &&
         parser.tree.openElements.isNotEmpty &&
         parser.tree.openElements.last.namespaceUri !=
             parser.tree.defaultNamespace) {
       var matched = true;
-      for (var expected in const ['C', 'D', 'A', 'T', 'A', '[']) {
+      for (var expected in const ["C", "D", "A", "T", "A", "["]) {
         charStack.add(stream.char());
         if (charStack.last != expected) {
           matched = false;
@@ -1330,7 +1329,7 @@
       }
     }
 
-    _addToken(ParseErrorToken('expected-dashes-or-doctype'));
+    _addToken(ParseErrorToken("expected-dashes-or-doctype"));
 
     while (charStack.isNotEmpty) {
       stream.unget(charStack.removeLast());
@@ -1341,17 +1340,17 @@
 
   bool commentStartState() {
     var data = stream.char();
-    if (data == '-') {
+    if (data == "-") {
       state = commentStartDashState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       currentStringToken.add('\uFFFD');
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('incorrect-comment'));
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("incorrect-comment"));
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-comment'));
+      _addToken(ParseErrorToken("eof-in-comment"));
       _addToken(currentToken);
       state = dataState;
     } else {
@@ -1363,17 +1362,17 @@
 
   bool commentStartDashState() {
     var data = stream.char();
-    if (data == '-') {
+    if (data == "-") {
       state = commentEndState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       currentStringToken.add('-\uFFFD');
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('incorrect-comment'));
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("incorrect-comment"));
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-comment'));
+      _addToken(ParseErrorToken("eof-in-comment"));
       _addToken(currentToken);
       state = dataState;
     } else {
@@ -1385,31 +1384,31 @@
 
   bool commentState() {
     var data = stream.char();
-    if (data == '-') {
+    if (data == "-") {
       state = commentEndDashState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       currentStringToken.add('\uFFFD');
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-comment'));
+      _addToken(ParseErrorToken("eof-in-comment"));
       _addToken(currentToken);
       state = dataState;
     } else {
-      currentStringToken.add(data).add(stream.charsUntil('-\u0000'));
+      currentStringToken.add(data).add(stream.charsUntil("-\u0000"));
     }
     return true;
   }
 
   bool commentEndDashState() {
     var data = stream.char();
-    if (data == '-') {
+    if (data == "-") {
       state = commentEndState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       currentStringToken.add('-\uFFFD');
       state = commentState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-comment-end-dash'));
+      _addToken(ParseErrorToken("eof-in-comment-end-dash"));
       _addToken(currentToken);
       state = dataState;
     } else {
@@ -1421,28 +1420,28 @@
 
   bool commentEndState() {
     var data = stream.char();
-    if (data == '>') {
+    if (data == ">") {
       _addToken(currentToken);
       state = dataState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       currentStringToken.add('--\uFFFD');
       state = commentState;
-    } else if (data == '!') {
+    } else if (data == "!") {
       _addToken(
-          ParseErrorToken('unexpected-bang-after-double-dash-in-comment'));
+          ParseErrorToken("unexpected-bang-after-double-dash-in-comment"));
       state = commentEndBangState;
-    } else if (data == '-') {
+    } else if (data == "-") {
       _addToken(
-          ParseErrorToken('unexpected-dash-after-double-dash-in-comment'));
+          ParseErrorToken("unexpected-dash-after-double-dash-in-comment"));
       currentStringToken.add(data);
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-comment-double-dash'));
+      _addToken(ParseErrorToken("eof-in-comment-double-dash"));
       _addToken(currentToken);
       state = dataState;
     } else {
       // XXX
-      _addToken(ParseErrorToken('unexpected-char-in-comment'));
+      _addToken(ParseErrorToken("unexpected-char-in-comment"));
       currentStringToken.add('--').add(data);
       state = commentState;
     }
@@ -1451,18 +1450,18 @@
 
   bool commentEndBangState() {
     var data = stream.char();
-    if (data == '>') {
+    if (data == ">") {
       _addToken(currentToken);
       state = dataState;
-    } else if (data == '-') {
+    } else if (data == "-") {
       currentStringToken.add('--!');
       state = commentEndDashState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
       currentStringToken.add('--!\uFFFD');
       state = commentState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-comment-end-bang-state'));
+      _addToken(ParseErrorToken("eof-in-comment-end-bang-state"));
       _addToken(currentToken);
       state = dataState;
     } else {
@@ -1477,12 +1476,12 @@
     if (isWhitespace(data)) {
       state = beforeDoctypeNameState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('expected-doctype-name-but-got-eof'));
+      _addToken(ParseErrorToken("expected-doctype-name-but-got-eof"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('need-space-after-doctype'));
+      _addToken(ParseErrorToken("need-space-after-doctype"));
       stream.unget(data);
       state = beforeDoctypeNameState;
     }
@@ -1493,17 +1492,17 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       return true;
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('expected-doctype-name-but-got-right-bracket'));
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("expected-doctype-name-but-got-right-bracket"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      currentDoctypeToken.name = '\uFFFD';
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.name = "\uFFFD";
       state = doctypeNameState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('expected-doctype-name-but-got-eof'));
+      _addToken(ParseErrorToken("expected-doctype-name-but-got-eof"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
@@ -1519,16 +1518,16 @@
     if (isWhitespace(data)) {
       currentDoctypeToken.name = asciiUpper2Lower(currentDoctypeToken.name);
       state = afterDoctypeNameState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       currentDoctypeToken.name = asciiUpper2Lower(currentDoctypeToken.name);
       _addToken(currentToken);
       state = dataState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      currentDoctypeToken.name = '${currentDoctypeToken.name}\uFFFD';
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.name = "${currentDoctypeToken.name}\uFFFD";
       state = doctypeNameState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype-name'));
+      _addToken(ParseErrorToken("eof-in-doctype-name"));
       currentDoctypeToken.correct = false;
       currentDoctypeToken.name = asciiUpper2Lower(currentDoctypeToken.name);
       _addToken(currentToken);
@@ -1543,20 +1542,20 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       return true;
-    } else if (data == '>') {
+    } else if (data == ">") {
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
       currentDoctypeToken.correct = false;
       stream.unget(data);
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       _addToken(currentToken);
       state = dataState;
     } else {
-      if (data == 'p' || data == 'P') {
+      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']) {
+        for (var expected in const ["uU", "bB", "lL", "iI", "cC"]) {
           data = stream.char();
           if (data == eof || !expected.contains(data)) {
             matched = false;
@@ -1567,9 +1566,9 @@
           state = afterDoctypePublicKeywordState;
           return true;
         }
-      } else if (data == 's' || data == 'S') {
+      } else if (data == "s" || data == "S") {
         var matched = true;
-        for (var expected in const ['yY', 'sS', 'tT', 'eE', 'mM']) {
+        for (var expected in const ["yY", "sS", "tT", "eE", "mM"]) {
           data = stream.char();
           if (data == eof || !expected.contains(data)) {
             matched = false;
@@ -1587,8 +1586,8 @@
       // discarded; only the latest character might be '>' or EOF
       // and needs to be ungetted
       stream.unget(data);
-      _addToken(ParseErrorToken('expected-space-or-right-bracket-in-doctype',
-          messageParams: {'data': data}));
+      _addToken(ParseErrorToken("expected-space-or-right-bracket-in-doctype",
+          messageParams: {"data": data}));
       currentDoctypeToken.correct = false;
       state = bogusDoctypeState;
     }
@@ -1600,11 +1599,11 @@
     if (isWhitespace(data)) {
       state = beforeDoctypePublicIdentifierState;
     } else if (data == "'" || data == '"') {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       stream.unget(data);
       state = beforeDoctypePublicIdentifierState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
@@ -1619,24 +1618,24 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       return true;
-    } else if (data == '"') {
-      currentDoctypeToken.publicId = '';
+    } else if (data == "\"") {
+      currentDoctypeToken.publicId = "";
       state = doctypePublicIdentifierDoubleQuotedState;
     } else if (data == "'") {
-      currentDoctypeToken.publicId = '';
+      currentDoctypeToken.publicId = "";
       state = doctypePublicIdentifierSingleQuotedState;
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("unexpected-end-of-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       currentDoctypeToken.correct = false;
       state = bogusDoctypeState;
     }
@@ -1647,16 +1646,16 @@
     var data = stream.char();
     if (data == '"') {
       state = afterDoctypePublicIdentifierState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}\uFFFD';
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.publicId = "${currentDoctypeToken.publicId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("unexpected-end-of-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
@@ -1670,16 +1669,16 @@
     var data = stream.char();
     if (data == "'") {
       state = afterDoctypePublicIdentifierState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}\uFFFD';
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.publicId = "${currentDoctypeToken.publicId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("unexpected-end-of-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
@@ -1693,24 +1692,24 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       state = betweenDoctypePublicAndSystemIdentifiersState;
-    } else if (data == '>') {
+    } else if (data == ">") {
       _addToken(currentToken);
       state = dataState;
     } else if (data == '"') {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
-      currentDoctypeToken.systemId = '';
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.systemId = "";
       state = doctypeSystemIdentifierDoubleQuotedState;
     } else if (data == "'") {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
-      currentDoctypeToken.systemId = '';
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
+      currentDoctypeToken.systemId = "";
       state = doctypeSystemIdentifierSingleQuotedState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       currentDoctypeToken.correct = false;
       state = bogusDoctypeState;
     }
@@ -1721,22 +1720,22 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       return true;
-    } else if (data == '>') {
+    } else if (data == ">") {
       _addToken(currentToken);
       state = dataState;
     } else if (data == '"') {
-      currentDoctypeToken.systemId = '';
+      currentDoctypeToken.systemId = "";
       state = doctypeSystemIdentifierDoubleQuotedState;
     } else if (data == "'") {
-      currentDoctypeToken.systemId = '';
+      currentDoctypeToken.systemId = "";
       state = doctypeSystemIdentifierSingleQuotedState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       currentDoctypeToken.correct = false;
       state = bogusDoctypeState;
     }
@@ -1748,11 +1747,11 @@
     if (isWhitespace(data)) {
       state = beforeDoctypeSystemIdentifierState;
     } else if (data == "'" || data == '"') {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       stream.unget(data);
       state = beforeDoctypeSystemIdentifierState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
@@ -1767,24 +1766,24 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       return true;
-    } else if (data == '"') {
-      currentDoctypeToken.systemId = '';
+    } else if (data == "\"") {
+      currentDoctypeToken.systemId = "";
       state = doctypeSystemIdentifierDoubleQuotedState;
     } else if (data == "'") {
-      currentDoctypeToken.systemId = '';
+      currentDoctypeToken.systemId = "";
       state = doctypeSystemIdentifierSingleQuotedState;
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       currentDoctypeToken.correct = false;
       state = bogusDoctypeState;
     }
@@ -1793,18 +1792,18 @@
 
   bool doctypeSystemIdentifierDoubleQuotedState() {
     var data = stream.char();
-    if (data == '"') {
+    if (data == "\"") {
       state = afterDoctypeSystemIdentifierState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}\uFFFD';
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.systemId = "${currentDoctypeToken.systemId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("unexpected-end-of-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
@@ -1818,16 +1817,16 @@
     var data = stream.char();
     if (data == "'") {
       state = afterDoctypeSystemIdentifierState;
-    } else if (data == '\u0000') {
-      _addToken(ParseErrorToken('invalid-codepoint'));
-      currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}\uFFFD';
-    } else if (data == '>') {
-      _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+    } else if (data == "\u0000") {
+      _addToken(ParseErrorToken("invalid-codepoint"));
+      currentDoctypeToken.systemId = "${currentDoctypeToken.systemId}\uFFFD";
+    } else if (data == ">") {
+      _addToken(ParseErrorToken("unexpected-end-of-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
@@ -1841,16 +1840,16 @@
     var data = stream.char();
     if (isWhitespace(data)) {
       return true;
-    } else if (data == '>') {
+    } else if (data == ">") {
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
-      _addToken(ParseErrorToken('eof-in-doctype'));
+      _addToken(ParseErrorToken("eof-in-doctype"));
       currentDoctypeToken.correct = false;
       _addToken(currentToken);
       state = dataState;
     } else {
-      _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+      _addToken(ParseErrorToken("unexpected-char-in-doctype"));
       state = bogusDoctypeState;
     }
     return true;
@@ -1858,7 +1857,7 @@
 
   bool bogusDoctypeState() {
     var data = stream.char();
-    if (data == '>') {
+    if (data == ">") {
       _addToken(currentToken);
       state = dataState;
     } else if (data == eof) {
@@ -1871,24 +1870,24 @@
   }
 
   bool cdataSectionState() {
-    var data = <String>[];
-    var matchedEnd = 0;
+    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(ParseErrorToken('invalid-codepoint'));
-        ch = '\uFFFD';
+      if (ch == "\u0000") {
+        _addToken(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) {
+      if (ch == "]" && matchedEnd < 2) {
         matchedEnd++;
-      } else if (ch == '>' && matchedEnd == 2) {
+      } else if (ch == ">" && matchedEnd == 2) {
         // Remove "]]>" from the end.
         data.removeLast();
         data.removeLast();
diff --git a/html/lib/src/treebuilder.dart b/html/lib/src/treebuilder.dart
index e096214..f6db7ad 100644
--- a/html/lib/src/treebuilder.dart
+++ b/html/lib/src/treebuilder.dart
@@ -21,9 +21,8 @@
   // Override the "add" method.
   // TODO(jmesserly): I'd rather not override this; can we do this in the
   // calling code instead?
-  @override
   void add(Element node) {
-    var equalCount = 0;
+    int equalCount = 0;
     if (node != Marker) {
       for (var element in reversed) {
         if (element == Marker) {
@@ -104,32 +103,32 @@
   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
-    var exactNode = target is Node;
+    bool exactNode = target is Node;
 
-    var listElements1 = scopingElements;
-    var listElements2 = const [];
-    var invert = false;
+    List listElements1 = scopingElements;
+    List listElements2 = const [];
+    bool invert = false;
     if (variant != null) {
       switch (variant) {
-        case 'button':
-          listElements2 = const [Pair(Namespaces.html, 'button')];
+        case "button":
+          listElements2 = const [Pair(Namespaces.html, "button")];
           break;
-        case 'list':
+        case "list":
           listElements2 = const [
-            Pair(Namespaces.html, 'ol'),
-            Pair(Namespaces.html, 'ul')
+            Pair(Namespaces.html, "ol"),
+            Pair(Namespaces.html, "ul")
           ];
           break;
-        case 'table':
+        case "table":
           listElements1 = const [
-            Pair(Namespaces.html, 'html'),
-            Pair(Namespaces.html, 'table')
+            Pair(Namespaces.html, "html"),
+            Pair(Namespaces.html, "table")
           ];
           break;
-        case 'select':
+        case "select":
           listElements1 = const [
-            Pair(Namespaces.html, 'optgroup'),
-            Pair(Namespaces.html, 'option')
+            Pair(Namespaces.html, "optgroup"),
+            Pair(Namespaces.html, "option")
           ];
           invert = true;
           break;
@@ -163,7 +162,7 @@
     }
 
     // Step 2 and step 3: we start with the last element. So i is -1.
-    var i = activeFormattingElements.length - 1;
+    int i = activeFormattingElements.length - 1;
     var entry = activeFormattingElements[i];
     if (entry == Marker || openElements.contains(entry)) {
       return;
@@ -243,14 +242,17 @@
   }
 
   void insertComment(StringToken token, [Node parent]) {
-    parent ??= openElements.last;
+    if (parent == null) {
+      parent = openElements.last;
+    }
     parent.nodes.add(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 ?? defaultNamespace;
+    var namespace = token.namespace;
+    if (namespace == null) namespace = defaultNamespace;
     var element = document.createElementNS(namespace, name)
       ..attributes = token.data
       ..sourceSpan = token.span;
@@ -264,7 +266,8 @@
 
   Element insertElementNormal(StartTagToken token) {
     var name = token.name;
-    var namespace = token.namespace ?? defaultNamespace;
+    var namespace = token.namespace;
+    if (namespace == null) namespace = defaultNamespace;
     var element = document.createElementNS(namespace, name)
       ..attributes = token.data
       ..sourceSpan = token.span;
@@ -329,7 +332,7 @@
         nodes.add(Text(data)..sourceSpan = span);
       }
     } else {
-      var index = nodes.indexOf(refNode);
+      int index = nodes.indexOf(refNode);
       if (index > 0 && nodes[index - 1] is Text) {
         Text last = nodes[index - 1];
         last.appendData(data);
@@ -349,7 +352,7 @@
     Node fosterParent;
     Node insertBefore;
     for (var elm in openElements.reversed) {
-      if (elm.localName == 'table') {
+      if (elm.localName == "table") {
         lastTable = elm;
         break;
       }
@@ -373,7 +376,7 @@
     var name = openElements.last.localName;
     // XXX td, th and tr are not actually needed
     if (name != exclude &&
-        const ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt']
+        const ["dd", "dt", "li", "option", "optgroup", "p", "rp", "rt"]
             .contains(name)) {
       openElements.removeLast();
       // XXX This is not entirely what the specification says. We should
diff --git a/html/lib/src/utils.dart b/html/lib/src/utils.dart
index 57124c8..54b578b 100644
--- a/html/lib/src/utils.dart
+++ b/html/lib/src/utils.dart
@@ -1,24 +1,51 @@
+/// Misc things that were useful when porting the code from Python.
+library utils;
+
 import 'constants.dart';
 
+typedef Predicate = bool Function();
+
 class Pair<F, S> {
   final F first;
   final S second;
 
   const Pair(this.first, this.second);
 
-  @override
   int get hashCode => 37 * first.hashCode + second.hashCode;
 
-  @override
   bool operator ==(other) => other.first == first && other.second == second;
 }
 
-bool startsWithAny(String str, List<String> prefixes) =>
-    prefixes.any(str.startsWith);
+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<T> slice<T>(List<T> list, int start, [int end]) {
-  end ??= list.length;
+  if (end == null) end = list.length;
   if (end < 0) end += list.length;
 
   // Ensure the indexes are in bounds.
@@ -28,7 +55,7 @@
 }
 
 bool allWhitespace(String str) {
-  for (var i = 0; i < str.length; i++) {
+  for (int i = 0; i < str.length; i++) {
     if (!isWhitespaceCC(str.codeUnitAt(i))) return false;
   }
   return true;
@@ -38,7 +65,7 @@
   if (str.length == size) return str;
   var result = StringBuffer();
   size -= str.length;
-  for (var i = 0; i < size; i++) {
+  for (int i = 0; i < size; i++) {
     result.write('0');
   }
   result.write(str);
@@ -56,11 +83,13 @@
     var result = StringBuffer();
     var search = '%($key)';
     int last = 0, match;
+    // This is a bug in the linter
+    // ignore: prefer_contains
     while ((match = format.indexOf(search, last)) >= 0) {
       result.write(format.substring(last, match));
       match += search.length;
 
-      var digits = match;
+      int digits = match;
       while (isDigit(format[digits])) {
         digits++;
       }
@@ -83,8 +112,8 @@
           result.write(padWithZeros(number, numberSize));
           break;
         default:
-          throw UnsupportedError('formatStr does not support format '
-              'character ${format[match]}');
+          throw UnsupportedError("formatStr does not support format "
+              "character ${format[match]}");
       }
 
       last = match + 1;
diff --git a/html/pubspec.yaml b/html/pubspec.yaml
index e7aa320..71f41db 100644
--- a/html/pubspec.yaml
+++ b/html/pubspec.yaml
@@ -1,5 +1,5 @@
 name: html
-version: 0.14.0+4
+version: 0.14.0+3
 
 description: APIs for parsing and manipulating HTML content outside the browser.
 author: Dart Team <misc@dartlang.org>
diff --git a/meta/.dart_tool/package_config.json b/meta/.dart_tool/package_config.json
new file mode 100644
index 0000000..f32f4a4
--- /dev/null
+++ b/meta/.dart_tool/package_config.json
@@ -0,0 +1,14 @@
+{
+  "configVersion": 2,
+  "packages": [
+    {
+      "name": "meta",
+      "rootUri": "../",
+      "packageUri": "lib/",
+      "languageVersion": "2.10"
+    }
+  ],
+  "generated": "2020-09-22T15:27:32.087775Z",
+  "generator": "pub",
+  "generatorVersion": "2.10.0-110.0.dev"
+}
diff --git a/meta/BUILD.gn b/meta/BUILD.gn
index c70aef4..1d3e68d 100644
--- a/meta/BUILD.gn
+++ b/meta/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for meta-1.3.0-nullsafety.4
+# This file is generated by importer.py for meta-1.3.0-nullsafety.3
 
 import("//build/dart/dart_library.gni")
 
diff --git a/meta/CHANGELOG.md b/meta/CHANGELOG.md
index d80e12b..9e27c00 100644
--- a/meta/CHANGELOG.md
+++ b/meta/CHANGELOG.md
@@ -1,8 +1,3 @@
-## 1.3.0-nullsafety.4
-
-* Introduce `@internal` to annotate elements that should not be used outside of
-  the package in which the element is declared.
-
 ## 1.3.0-nullsafety.3
 
 * Allow 2.10 stable and 2.11.0 dev SDK versions.
diff --git a/meta/lib/meta.dart b/meta/lib/meta.dart
index c6dff3b..11652e1 100644
--- a/meta/lib/meta.dart
+++ b/meta/lib/meta.dart
@@ -126,20 +126,6 @@
 ///   class that has this annotation is not immutable.
 const Immutable immutable = Immutable();
 
-/// Used to annotate a declaration which should only be used from within the
-/// package in which it is declared, and which should not be exposed from said
-/// package's public API.
-///
-/// Tools, such as the analyzer, can provide feedback if
-///
-/// * the declaration is declared in a package's public API, or is exposed from
-///   a package's public API, or
-/// * the declaration is private, an unnamed extension, a static member of a
-///   private class, mixin, or extension, a value of a private enum, or a
-///   constructor of a private class, or
-/// * the declaration is referenced outside the package in which it is declared.
-const _Internal internal = _Internal();
-
 /// Used to annotate a test framework function that runs a single test.
 ///
 /// Tools, such as IDEs, can show invocations of such function in a file
@@ -271,15 +257,15 @@
 /// * the member is referenced outside of the defining library.
 const _VisibleForOverriding visibleForOverriding = _VisibleForOverriding();
 
-/// Used to annotate a declaration that was made public, so that it is more
-/// visible than otherwise necessary, to make code testable.
+/// Used to annotate a declaration was made public, so that it is more visible
+/// than otherwise necessary, to make code testable.
 ///
 /// Tools, such as the analyzer, can provide feedback if
 ///
 /// * the annotation is associated with a declaration not in the `lib` folder
 ///   of a package, or a private declaration, or a declaration in an unnamed
 ///   static extension, or
-/// * the declaration is referenced outside of its defining library or a
+/// * the declaration is referenced outside of its the defining library or a
 ///   library which is in the `test` folder of the defining package.
 const _VisibleForTesting visibleForTesting = _VisibleForTesting();
 
@@ -340,10 +326,6 @@
   const _Factory();
 }
 
-class _Internal {
-  const _Internal();
-}
-
 class _IsTest {
   const _IsTest();
 }
diff --git a/meta/pubspec.yaml b/meta/pubspec.yaml
index 28a9847..be6237c 100644
--- a/meta/pubspec.yaml
+++ b/meta/pubspec.yaml
@@ -1,5 +1,5 @@
 name: meta
-version: 1.3.0-nullsafety.4
+version: 1.3.0-nullsafety.3
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/meta
 description: >
  This library contains the declarations of annotations that developers can use
diff --git a/package_config.json b/package_config.json
index 30d1c98..ced66e0 100644
--- a/package_config.json
+++ b/package_config.json
@@ -87,6 +87,12 @@
       "rootUri": "./charcode/"
     }, 
     {
+      "languageVersion": "2.3", 
+      "name": "checked_yaml", 
+      "packageUri": "lib/", 
+      "rootUri": "./checked_yaml/"
+    }, 
+    {
       "languageVersion": "2.0", 
       "name": "cli_util", 
       "packageUri": "lib/", 
@@ -202,6 +208,12 @@
     }, 
     {
       "languageVersion": "2.1", 
+      "name": "file_testing", 
+      "packageUri": "lib/", 
+      "rootUri": "./file_testing/"
+    }, 
+    {
+      "languageVersion": "2.1", 
       "name": "fixnum", 
       "packageUri": "lib/", 
       "rootUri": "./fixnum/"
@@ -525,6 +537,12 @@
       "rootUri": "./pub_semver/"
     }, 
     {
+      "languageVersion": "2.2", 
+      "name": "pubspec_parse", 
+      "packageUri": "lib/", 
+      "rootUri": "./pubspec_parse/"
+    }, 
+    {
       "languageVersion": "2.0", 
       "name": "quiver", 
       "packageUri": "lib/", 
diff --git a/pubspec_parse/.gitignore b/pubspec_parse/.gitignore
new file mode 100644
index 0000000..ec8eae3
--- /dev/null
+++ b/pubspec_parse/.gitignore
@@ -0,0 +1,4 @@
+# Don’t commit the following directories created by pub.
+.dart_tool/
+.packages
+pubspec.lock
diff --git a/pubspec_parse/.travis.yml b/pubspec_parse/.travis.yml
new file mode 100644
index 0000000..ccb1caf
--- /dev/null
+++ b/pubspec_parse/.travis.yml
@@ -0,0 +1,29 @@
+language: dart
+
+dart:
+  - 2.2.0
+  - dev
+
+dart_task:
+  - test: -x presubmit-only
+  - test: --run-skipped -t presubmit-only
+
+matrix:
+  include:
+    # Only validate formatting using the dev release
+    - dart: dev
+      dart_task: dartfmt
+    - dart: dev
+      dart_task:
+        dartanalyzer: --fatal-infos --fatal-warnings .
+    - dart: 2.2.0
+      dart_task:
+        dartanalyzer: --fatal-warnings .
+
+# Only building master means that we don't run two builds for each pull request.
+branches:
+  only: [master]
+
+cache:
+  directories:
+    - $HOME/.pub-cache
diff --git a/pubspec_parse/BUILD.gn b/pubspec_parse/BUILD.gn
new file mode 100644
index 0000000..49dae35
--- /dev/null
+++ b/pubspec_parse/BUILD.gn
@@ -0,0 +1,26 @@
+# This file is generated by importer.py for pubspec_parse-0.1.5
+
+import("//build/dart/dart_library.gni")
+
+dart_library("pubspec_parse") {
+  package_name = "pubspec_parse"
+
+  language_version = "2.2"
+
+  disable_analysis = true
+
+  deps = [
+    "//third_party/dart-pkg/pub/yaml",
+    "//third_party/dart-pkg/pub/json_annotation",
+    "//third_party/dart-pkg/pub/pub_semver",
+    "//third_party/dart-pkg/pub/checked_yaml",
+  ]
+
+  sources = [
+    "pubspec_parse.dart",
+    "src/dependency.dart",
+    "src/dependency.g.dart",
+    "src/pubspec.dart",
+    "src/pubspec.g.dart",
+  ]
+}
diff --git a/pubspec_parse/CHANGELOG.md b/pubspec_parse/CHANGELOG.md
new file mode 100644
index 0000000..f2c2542
--- /dev/null
+++ b/pubspec_parse/CHANGELOG.md
@@ -0,0 +1,42 @@
+## 0.1.5
+
+- Update SDK requirement to `>=2.2.0 <3.0.0`.
+- Support the latest `package:json_annotation`.
+
+## 0.1.4
+
+- Added `lenient` named argument to `Pubspec.fromJson` to ignore format and type errors. 
+
+## 0.1.3
+
+- Added support for `flutter`, `issue_tracker`, `publish_to`, and `repository`
+  fields.
+
+## 0.1.2+3
+
+- Support the latest version of `package:json_annotation`.
+
+## 0.1.2+2
+
+- Support `package:json_annotation` v1.
+
+## 0.1.2+1
+
+- Support the Dart 2 stable release.
+
+## 0.1.2
+
+- Allow superfluous `version` keys with `git` and `path` dependencies.
+- Improve errors when unsupported keys are provided in dependencies.
+- Provide better errors with invalid `sdk` dependency values.
+- Support "scp-like syntax" for Git SSH URIs in the form
+  `[user@]host.xz:path/to/repo.git/`.
+
+## 0.1.1
+
+- Fixed name collision with error type in latest `package:json_annotation`.
+- Improved parsing of hosted dependencies and environment constraints.
+
+## 0.1.0
+
+- Initial release.
diff --git a/pubspec_parse/LICENSE b/pubspec_parse/LICENSE
new file mode 100644
index 0000000..c4dc9ba
--- /dev/null
+++ b/pubspec_parse/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2018, 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:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pubspec_parse/README.md b/pubspec_parse/README.md
new file mode 100644
index 0000000..a95459c
--- /dev/null
+++ b/pubspec_parse/README.md
@@ -0,0 +1,13 @@
+[![Build Status](https://travis-ci.org/dart-lang/pubspec_parse.svg?branch=master)](https://travis-ci.org/dart-lang/pubspec_parse)
+
+Supports parsing `pubspec.yaml` files with robust error reporting and support
+for most of the documented features.
+
+Read more about the
+[pubspec format](https://www.dartlang.org/tools/pub/pubspec).
+
+## Features and bugs
+
+Please file feature requests and bugs at the [issue tracker].
+
+[issue tracker]: https://github.com/dart-lang/pubspec_parse/issues
diff --git a/pubspec_parse/analysis_options.yaml b/pubspec_parse/analysis_options.yaml
new file mode 100644
index 0000000..f983bb3
--- /dev/null
+++ b/pubspec_parse/analysis_options.yaml
@@ -0,0 +1,99 @@
+include: package:pedantic/analysis_options.yaml
+analyzer:
+  strong-mode:
+    implicit-casts: false
+  errors:
+    dead_code: error
+    override_on_non_overriding_method: error
+    unused_element: error
+    unused_import: error
+    unused_local_variable: error
+linter:
+  rules:
+    - always_declare_return_types
+    - annotate_overrides
+    - avoid_bool_literals_in_conditional_expressions
+    - avoid_classes_with_only_static_members
+    - avoid_empty_else
+    - avoid_function_literals_in_foreach_calls
+    - avoid_init_to_null
+    - avoid_null_checks_in_equality_operators
+    - avoid_relative_lib_imports
+    - avoid_renaming_method_parameters
+    - avoid_return_types_on_setters
+    - avoid_returning_null
+    - avoid_returning_null_for_future
+    - avoid_returning_null_for_void
+    - avoid_returning_this
+    - avoid_shadowing_type_parameters
+    - avoid_single_cascade_in_expression_statements
+    - avoid_types_as_parameter_names
+    - avoid_unused_constructor_parameters
+    - await_only_futures
+    - camel_case_types
+    - cancel_subscriptions
+    - cascade_invocations
+    - comment_references
+    - constant_identifier_names
+    - control_flow_in_finally
+    - directives_ordering
+    - empty_catches
+    - empty_constructor_bodies
+    - empty_statements
+    - file_names
+    - hash_and_equals
+    - implementation_imports
+    - invariant_booleans
+    - iterable_contains_unrelated_type
+    - join_return_with_assignment
+    - library_names
+    - library_prefixes
+    - list_remove_unrelated_type
+    - literal_only_boolean_expressions
+    - no_adjacent_strings_in_list
+    - no_duplicate_case_values
+    - non_constant_identifier_names
+    - null_closures
+    - omit_local_variable_types
+    - only_throw_errors
+    - overridden_fields
+    - package_api_docs
+    - package_names
+    - package_prefixed_library_names
+    - prefer_adjacent_string_concatenation
+    - prefer_collection_literals
+    - prefer_conditional_assignment
+    - prefer_const_constructors
+    - prefer_contains
+    - prefer_equal_for_default_values
+    - prefer_final_fields
+    - prefer_final_locals
+    - prefer_generic_function_type_aliases
+    - prefer_initializing_formals
+    - prefer_interpolation_to_compose_strings
+    - prefer_is_empty
+    - prefer_is_not_empty
+    - prefer_null_aware_operators
+    - prefer_single_quotes
+    - prefer_typing_uninitialized_variables
+    - recursive_getters
+    - slash_for_doc_comments
+    - test_types_in_equals
+    - throw_in_finally
+    - type_init_formals
+    - unawaited_futures
+    - unnecessary_await_in_return
+    - unnecessary_brace_in_string_interps
+    - unnecessary_const
+    - unnecessary_getters_setters
+    - unnecessary_lambdas
+    - unnecessary_new
+    - unnecessary_null_aware_assignments
+    - unnecessary_parenthesis
+    - unnecessary_statements
+    - unnecessary_this
+    - unrelated_type_equality_checks
+    - use_function_type_syntax_for_parameters
+    - use_rethrow_when_possible
+    - valid_regexps
+    - void_checks
diff --git a/pubspec_parse/build.yaml b/pubspec_parse/build.yaml
new file mode 100644
index 0000000..1525ab8
--- /dev/null
+++ b/pubspec_parse/build.yaml
@@ -0,0 +1,14 @@
+# Read about `build.yaml` at https://pub.dartlang.org/packages/build_config
+# To update generated code, run `pub run build_runner build`
+targets:
+  $default:
+    builders:
+      json_serializable:
+        generate_for:
+          - lib/src/pubspec.dart
+          - lib/src/dependency.dart
+        options:
+          any_map: true
+          checked: true
+          create_to_json: false
+          field_rename: snake
diff --git a/pubspec_parse/dart_test.yaml b/pubspec_parse/dart_test.yaml
new file mode 100644
index 0000000..1d7ac69
--- /dev/null
+++ b/pubspec_parse/dart_test.yaml
@@ -0,0 +1,3 @@
+tags:
+  presubmit-only:
+    skip: "Should only be run during presubmit"
diff --git a/pubspec_parse/lib/pubspec_parse.dart b/pubspec_parse/lib/pubspec_parse.dart
new file mode 100644
index 0000000..132263a
--- /dev/null
+++ b/pubspec_parse/lib/pubspec_parse.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2018, 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.
+
+export 'src/dependency.dart'
+    show
+        Dependency,
+        HostedDependency,
+        GitDependency,
+        SdkDependency,
+        PathDependency;
+export 'src/pubspec.dart' show Pubspec;
diff --git a/pubspec_parse/lib/src/dependency.dart b/pubspec_parse/lib/src/dependency.dart
new file mode 100644
index 0000000..2d4eda6
--- /dev/null
+++ b/pubspec_parse/lib/src/dependency.dart
@@ -0,0 +1,221 @@
+// Copyright (c) 2018, 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:json_annotation/json_annotation.dart';
+import 'package:pub_semver/pub_semver.dart';
+import 'package:yaml/yaml.dart';
+
+part 'dependency.g.dart';
+
+Map<String, Dependency> parseDeps(Map source) =>
+    source?.map((k, v) {
+      final key = k as String;
+      Dependency value;
+      try {
+        value = _fromJson(v);
+      } on CheckedFromJsonException catch (e) {
+        if (e.map is! YamlMap) {
+          // This is likely a "synthetic" map created from a String value
+          // Use `source` to throw this exception with an actual YamlMap and
+          // extract the associated error information.
+          throw CheckedFromJsonException(source, key, e.className, e.message);
+        }
+        rethrow;
+      }
+
+      if (value == null) {
+        throw CheckedFromJsonException(
+            source, key, 'Pubspec', 'Not a valid dependency value.');
+      }
+      return MapEntry(key, value);
+    }) ??
+    {};
+
+const _sourceKeys = ['sdk', 'git', 'path', 'hosted'];
+
+/// Returns `null` if the data could not be parsed.
+Dependency _fromJson(dynamic data) {
+  if (data is String || data == null) {
+    return _$HostedDependencyFromJson({'version': data});
+  }
+
+  if (data is Map) {
+    final matchedKeys =
+        data.keys.cast<String>().where((key) => key != 'version').toList();
+
+    if (data.isEmpty || (matchedKeys.isEmpty && data.containsKey('version'))) {
+      return _$HostedDependencyFromJson(data);
+    } else {
+      final firstUnrecognizedKey = matchedKeys
+          .firstWhere((k) => !_sourceKeys.contains(k), orElse: () => null);
+
+      return $checkedNew<Dependency>('Dependency', data, () {
+        if (firstUnrecognizedKey != null) {
+          throw UnrecognizedKeysException(
+              [firstUnrecognizedKey], data, _sourceKeys);
+        }
+        if (matchedKeys.length > 1) {
+          throw CheckedFromJsonException(data, matchedKeys[1], 'Dependency',
+              'A dependency may only have one source.');
+        }
+
+        final key = matchedKeys.single;
+
+        switch (key) {
+          case 'git':
+            return GitDependency.fromData(data[key]);
+          case 'path':
+            return PathDependency.fromData(data[key]);
+          case 'sdk':
+            return _$SdkDependencyFromJson(data);
+          case 'hosted':
+            return _$HostedDependencyFromJson(data);
+        }
+        throw StateError('There is a bug in pubspec_parse.');
+      });
+    }
+  }
+
+  // Not a String or a Map – return null so parent logic can throw proper error
+  return null;
+}
+
+abstract class Dependency {
+  Dependency._();
+
+  String get _info;
+
+  @override
+  String toString() => '$runtimeType: $_info';
+}
+
+@JsonSerializable()
+class SdkDependency extends Dependency {
+  @JsonKey(nullable: false, disallowNullValue: true, required: true)
+  final String sdk;
+  @JsonKey(fromJson: _constraintFromString)
+  final VersionConstraint version;
+
+  SdkDependency(this.sdk, {this.version}) : super._();
+
+  @override
+  String get _info => sdk;
+}
+
+@JsonSerializable()
+class GitDependency extends Dependency {
+  @JsonKey(fromJson: parseGitUri, required: true, disallowNullValue: true)
+  final Uri url;
+  final String ref;
+  final String path;
+
+  GitDependency(this.url, this.ref, this.path) : super._();
+
+  factory GitDependency.fromData(Object data) {
+    if (data is String) {
+      data = {'url': data};
+    }
+
+    if (data is Map) {
+      return _$GitDependencyFromJson(data);
+    }
+
+    throw ArgumentError.value(data, 'git', 'Must be a String or a Map.');
+  }
+
+  @override
+  String get _info => 'url@$url';
+}
+
+Uri parseGitUri(String value) =>
+    value == null ? null : _tryParseScpUri(value) ?? Uri.parse(value);
+
+/// Supports URIs like `[user@]host.xz:path/to/repo.git/`
+/// See https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a
+Uri _tryParseScpUri(String value) {
+  final colonIndex = value.indexOf(':');
+
+  if (colonIndex < 0) {
+    return null;
+  } else if (colonIndex == value.indexOf('://')) {
+    // If the first colon is part of a scheme, it's not an scp-like URI
+    return null;
+  }
+  final slashIndex = value.indexOf('/');
+
+  if (slashIndex >= 0 && slashIndex < colonIndex) {
+    // Per docs: This syntax is only recognized if there are no slashes before
+    // the first colon. This helps differentiate a local path that contains a
+    // colon. For example the local path foo:bar could be specified as an
+    // absolute path or ./foo:bar to avoid being misinterpreted as an ssh url.
+    return null;
+  }
+
+  final atIndex = value.indexOf('@');
+  if (colonIndex > atIndex) {
+    final user = atIndex >= 0 ? value.substring(0, atIndex) : null;
+    final host = value.substring(atIndex + 1, colonIndex);
+    final path = value.substring(colonIndex + 1);
+    return Uri(scheme: 'ssh', userInfo: user, host: host, path: path);
+  }
+  return null;
+}
+
+class PathDependency extends Dependency {
+  final String path;
+
+  PathDependency(this.path) : super._();
+
+  factory PathDependency.fromData(Object data) {
+    if (data is String) {
+      return PathDependency(data);
+    }
+    throw ArgumentError.value(data, 'path', 'Must be a String.');
+  }
+
+  @override
+  String get _info => 'path@$path';
+}
+
+@JsonSerializable(disallowUnrecognizedKeys: true)
+class HostedDependency extends Dependency {
+  @JsonKey(fromJson: _constraintFromString)
+  final VersionConstraint version;
+
+  @JsonKey(disallowNullValue: true)
+  final HostedDetails hosted;
+
+  HostedDependency({VersionConstraint version, this.hosted})
+      : version = version ?? VersionConstraint.any,
+        super._();
+
+  @override
+  String get _info => version.toString();
+}
+
+@JsonSerializable(disallowUnrecognizedKeys: true)
+class HostedDetails {
+  @JsonKey(required: true, disallowNullValue: true)
+  final String name;
+
+  @JsonKey(fromJson: parseGitUri, disallowNullValue: true)
+  final Uri url;
+
+  HostedDetails(this.name, this.url);
+
+  factory HostedDetails.fromJson(Object data) {
+    if (data is String) {
+      data = {'name': data};
+    }
+
+    if (data is Map) {
+      return _$HostedDetailsFromJson(data);
+    }
+
+    throw ArgumentError.value(data, 'hosted', 'Must be a Map or String.');
+  }
+}
+
+VersionConstraint _constraintFromString(String input) =>
+    input == null ? null : VersionConstraint.parse(input);
diff --git a/pubspec_parse/lib/src/dependency.g.dart b/pubspec_parse/lib/src/dependency.g.dart
new file mode 100644
index 0000000..4e137fa
--- /dev/null
+++ b/pubspec_parse/lib/src/dependency.g.dart
@@ -0,0 +1,62 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'dependency.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SdkDependency _$SdkDependencyFromJson(Map json) {
+  return $checkedNew('SdkDependency', json, () {
+    $checkKeys(json,
+        requiredKeys: const ['sdk'], disallowNullValues: const ['sdk']);
+    final val = SdkDependency(
+      $checkedConvert(json, 'sdk', (v) => v as String),
+      version: $checkedConvert(
+          json, 'version', (v) => _constraintFromString(v as String)),
+    );
+    return val;
+  });
+}
+
+GitDependency _$GitDependencyFromJson(Map json) {
+  return $checkedNew('GitDependency', json, () {
+    $checkKeys(json,
+        requiredKeys: const ['url'], disallowNullValues: const ['url']);
+    final val = GitDependency(
+      $checkedConvert(json, 'url', (v) => parseGitUri(v as String)),
+      $checkedConvert(json, 'ref', (v) => v as String),
+      $checkedConvert(json, 'path', (v) => v as String),
+    );
+    return val;
+  });
+}
+
+HostedDependency _$HostedDependencyFromJson(Map json) {
+  return $checkedNew('HostedDependency', json, () {
+    $checkKeys(json,
+        allowedKeys: const ['version', 'hosted'],
+        disallowNullValues: const ['hosted']);
+    final val = HostedDependency(
+      version: $checkedConvert(
+          json, 'version', (v) => _constraintFromString(v as String)),
+      hosted: $checkedConvert(
+          json, 'hosted', (v) => v == null ? null : HostedDetails.fromJson(v)),
+    );
+    return val;
+  });
+}
+
+HostedDetails _$HostedDetailsFromJson(Map json) {
+  return $checkedNew('HostedDetails', json, () {
+    $checkKeys(json,
+        allowedKeys: const ['name', 'url'],
+        requiredKeys: const ['name'],
+        disallowNullValues: const ['name', 'url']);
+    final val = HostedDetails(
+      $checkedConvert(json, 'name', (v) => v as String),
+      $checkedConvert(json, 'url', (v) => parseGitUri(v as String)),
+    );
+    return val;
+  });
+}
diff --git a/pubspec_parse/lib/src/pubspec.dart b/pubspec_parse/lib/src/pubspec.dart
new file mode 100644
index 0000000..7358389
--- /dev/null
+++ b/pubspec_parse/lib/src/pubspec.dart
@@ -0,0 +1,198 @@
+// Copyright (c) 2018, 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:checked_yaml/checked_yaml.dart';
+import 'package:json_annotation/json_annotation.dart';
+import 'package:pub_semver/pub_semver.dart';
+
+import 'dependency.dart';
+
+part 'pubspec.g.dart';
+
+@JsonSerializable()
+class Pubspec {
+  // TODO: executables
+
+  final String name;
+
+  @JsonKey(fromJson: _versionFromString)
+  final Version version;
+
+  final String description;
+
+  /// This should be a URL pointing to the website for the package.
+  final String homepage;
+
+  /// Specifies where to publish this package.
+  ///
+  /// Accepted values: `null`, `'none'` or an `http` or `https` URL.
+  ///
+  /// If not specified, the pub client defaults to `https://pub.dartlang.org`.
+  ///
+  /// [More information](https://www.dartlang.org/tools/pub/pubspec#publish_to).
+  final String publishTo;
+
+  /// Optional field to specify the source code repository of the package.
+  /// Useful when a package has both a home page and a repository.
+  final Uri repository;
+
+  /// Optional field to a web page where developers can report new issues or
+  /// view existing ones.
+  final Uri issueTracker;
+
+  /// If there is exactly 1 value in [authors], returns it.
+  ///
+  /// If there are 0 or more than 1, returns `null`.
+  @Deprecated(
+      'Here for completeness, but not recommended. Use `authors` instead.')
+  String get author {
+    if (authors.length == 1) {
+      return authors.single;
+    }
+    return null;
+  }
+
+  final List<String> authors;
+  final String documentation;
+
+  @JsonKey(fromJson: _environmentMap)
+  final Map<String, VersionConstraint> environment;
+
+  @JsonKey(fromJson: parseDeps, nullable: false)
+  final Map<String, Dependency> dependencies;
+
+  @JsonKey(fromJson: parseDeps, nullable: false)
+  final Map<String, Dependency> devDependencies;
+
+  @JsonKey(fromJson: parseDeps, nullable: false)
+  final Map<String, Dependency> dependencyOverrides;
+
+  /// Optional configuration specific to [Flutter](https://flutter.io/)
+  /// packages.
+  ///
+  /// May include
+  /// [assets](https://flutter.io/docs/development/ui/assets-and-images)
+  /// and other settings.
+  final Map<String, dynamic> flutter;
+
+  /// If [author] and [authors] are both provided, their values are combined
+  /// with duplicates eliminated.
+  Pubspec(
+    this.name, {
+    this.version,
+    this.publishTo,
+    String author,
+    List<String> authors,
+    Map<String, VersionConstraint> environment,
+    this.homepage,
+    this.repository,
+    this.issueTracker,
+    this.documentation,
+    this.description,
+    Map<String, Dependency> dependencies,
+    Map<String, Dependency> devDependencies,
+    Map<String, Dependency> dependencyOverrides,
+    this.flutter,
+  })  : authors = _normalizeAuthors(author, authors),
+        environment = environment ?? const {},
+        dependencies = dependencies ?? const {},
+        devDependencies = devDependencies ?? const {},
+        dependencyOverrides = dependencyOverrides ?? const {} {
+    if (name == null || name.isEmpty) {
+      throw ArgumentError.value(name, 'name', '"name" cannot be empty.');
+    }
+
+    if (publishTo != null && publishTo != 'none') {
+      try {
+        final targetUri = Uri.parse(publishTo);
+        if (!(targetUri.isScheme('http') || targetUri.isScheme('https'))) {
+          throw const FormatException('Must be an http or https URL.');
+        }
+      } on FormatException catch (e) {
+        throw ArgumentError.value(publishTo, 'publishTo', e.message);
+      }
+    }
+  }
+
+  factory Pubspec.fromJson(Map json, {bool lenient = false}) {
+    lenient ??= false;
+
+    if (lenient) {
+      while (json.isNotEmpty) {
+        // Attempting to remove top-level properties that cause parsing errors.
+        try {
+          return _$PubspecFromJson(json);
+        } on CheckedFromJsonException catch (e) {
+          if (e.map == json && json.containsKey(e.key)) {
+            json = Map.from(json)..remove(e.key);
+            continue;
+          }
+          rethrow;
+        }
+      }
+    }
+
+    return _$PubspecFromJson(json);
+  }
+
+  /// Parses source [yaml] into [Pubspec].
+  ///
+  /// When [lenient] is set, top-level property-parsing or type cast errors are
+  /// ignored and `null` values are returned.
+  factory Pubspec.parse(String yaml, {sourceUrl, bool lenient = false}) {
+    lenient ??= false;
+
+    return checkedYamlDecode(
+        yaml, (map) => Pubspec.fromJson(map, lenient: lenient),
+        sourceUrl: sourceUrl);
+  }
+
+  static List<String> _normalizeAuthors(String author, List<String> authors) {
+    final value = <String>{};
+    if (author != null) {
+      value.add(author);
+    }
+    if (authors != null) {
+      value.addAll(authors);
+    }
+    return value.toList();
+  }
+}
+
+Version _versionFromString(String input) =>
+    input == null ? null : Version.parse(input);
+
+Map<String, VersionConstraint> _environmentMap(Map source) =>
+    source?.map((k, value) {
+      final key = k as String;
+      if (key == 'dart') {
+        // github.com/dart-lang/pub/blob/d84173eeb03c3/lib/src/pubspec.dart#L342
+        // 'dart' is not allowed as a key!
+        throw CheckedFromJsonException(
+          source,
+          'dart',
+          'VersionConstraint',
+          'Use "sdk" to for Dart SDK constraints.',
+          badKey: true,
+        );
+      }
+
+      VersionConstraint constraint;
+      if (value == null) {
+        constraint = null;
+      } else if (value is String) {
+        try {
+          constraint = VersionConstraint.parse(value);
+        } on FormatException catch (e) {
+          throw CheckedFromJsonException(source, key, 'Pubspec', e.message);
+        }
+
+        return MapEntry(key, constraint);
+      } else {
+        throw CheckedFromJsonException(
+            source, key, 'VersionConstraint', '`$value` is not a String.');
+      }
+
+      return MapEntry(key, constraint);
+    });
diff --git a/pubspec_parse/lib/src/pubspec.g.dart b/pubspec_parse/lib/src/pubspec.g.dart
new file mode 100644
index 0000000..eb062b8
--- /dev/null
+++ b/pubspec_parse/lib/src/pubspec.g.dart
@@ -0,0 +1,48 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'pubspec.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Pubspec _$PubspecFromJson(Map json) {
+  return $checkedNew('Pubspec', json, () {
+    final val = Pubspec(
+      $checkedConvert(json, 'name', (v) => v as String),
+      version: $checkedConvert(
+          json, 'version', (v) => _versionFromString(v as String)),
+      publishTo: $checkedConvert(json, 'publish_to', (v) => v as String),
+      author: $checkedConvert(json, 'author', (v) => v as String),
+      authors: $checkedConvert(json, 'authors',
+          (v) => (v as List)?.map((e) => e as String)?.toList()),
+      environment: $checkedConvert(
+          json, 'environment', (v) => _environmentMap(v as Map)),
+      homepage: $checkedConvert(json, 'homepage', (v) => v as String),
+      repository: $checkedConvert(
+          json, 'repository', (v) => v == null ? null : Uri.parse(v as String)),
+      issueTracker: $checkedConvert(json, 'issue_tracker',
+          (v) => v == null ? null : Uri.parse(v as String)),
+      documentation: $checkedConvert(json, 'documentation', (v) => v as String),
+      description: $checkedConvert(json, 'description', (v) => v as String),
+      dependencies:
+          $checkedConvert(json, 'dependencies', (v) => parseDeps(v as Map)),
+      devDependencies:
+          $checkedConvert(json, 'dev_dependencies', (v) => parseDeps(v as Map)),
+      dependencyOverrides: $checkedConvert(
+          json, 'dependency_overrides', (v) => parseDeps(v as Map)),
+      flutter: $checkedConvert(
+          json,
+          'flutter',
+          (v) => (v as Map)?.map(
+                (k, e) => MapEntry(k as String, e),
+              )),
+    );
+    return val;
+  }, fieldKeyMap: const {
+    'publishTo': 'publish_to',
+    'issueTracker': 'issue_tracker',
+    'devDependencies': 'dev_dependencies',
+    'dependencyOverrides': 'dependency_overrides'
+  });
+}
diff --git a/pubspec_parse/pubspec.yaml b/pubspec_parse/pubspec.yaml
new file mode 100644
index 0000000..fc54d12
--- /dev/null
+++ b/pubspec_parse/pubspec.yaml
@@ -0,0 +1,28 @@
+name: pubspec_parse
+description: >-
+  Simple package for parsing pubspec.yaml files with a type-safe API and rich
+  error reporting.
+version: 0.1.5
+homepage: https://github.com/dart-lang/pubspec_parse
+author: Dart Team <misc@dartlang.org>
+
+environment:
+  sdk: '>=2.2.0 <3.0.0'
+
+dependencies:
+  checked_yaml: ^1.0.0
+  # Verified that no new features since 1.0.0 are used - be careful!
+  json_annotation: '>=1.0.0 <4.0.0'
+  pub_semver: ^1.3.2
+  yaml: ^2.1.12
+
+dev_dependencies:
+  build_runner: ^1.0.0
+  build_verify: ^1.0.0
+  json_serializable: ^3.0.0
+  path: ^1.5.1
+  pedantic: ^1.4.0
+  stack_trace: ^1.9.2
+  test: ^1.0.0
+  test_descriptor: ^1.0.3
+  test_process: ^1.0.2